Merge "Cleanup RpcRoutingStrategy definition"
authorTony Tkacik <ttkacik@cisco.com>
Mon, 27 Oct 2014 09:28:04 +0000 (09:28 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Mon, 27 Oct 2014 09:28:04 +0000 (09:28 +0000)
222 files changed:
features/base/src/main/resources/features.xml
features/netconf-connector/pom.xml
opendaylight/commons/opendaylight/pom.xml
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ReconnectPromise.java
opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/protocol/framework/ServerTest.java
opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/IdentityAttributeRef.java
opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/ObjectNameUtil.java
opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/constants/ConfigRegistryConstants.java
opendaylight/config/config-api/src/main/yang/config.yang
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImpl.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImpl.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/DeadlockMonitor.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ServiceReferenceRegistryImpl.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverImpl.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverManager.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DestroyedModule.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AbstractDynamicWrapper.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AnnotationsHelper.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AttributeHolder.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/DynamicReadableWrapper.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/DynamicWritableWrapper.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/InternalJMXRegistrator.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/ModuleJMXRegistrator.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BeanToOsgiServiceManager.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BlankTransactionServiceTracker.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BundleContextBackedModuleFactoriesResolver.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ModuleFactoryBundleTracker.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/mapping/ModuleInfoBundleTracker.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/InterfacesHelper.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/LookupBeansUtil.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/ModuleQNameUtil.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/util/OsgiRegistrationUtil.java
opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/AbstractFeatureWrapper.java
opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ChildAwareFeatureWrapper.java
opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ConfigFeaturesListener.java
opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ConfigPusherCustomizer.java
opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ConfigPushingRunnable.java
opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/FeatureConfigPusher.java
opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/XmlFileStorageAdapter.java
opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/ConfigSnapshot.java
opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/StringTrimAdapter.java
opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigRegistryJMXClient.java
opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigTransactionJMXClient.java
opendaylight/config/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/ContextSetterImpl.java
opendaylight/config/logback-config/src/main/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleFactory.java
opendaylight/config/netty-event-executor-config/src/test/java/org/opendaylight/controller/config/yang/netty/eventexecutor/ImmediateEventExecutorModuleTest.java
opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/CodeWriter.java
opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/JMXGenerator.java
opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/AbstractFactoryTemplate.java
opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/RuntimeRegistratorFtlTemplate.java
opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/TemplateFactory.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ConfigConstants.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryBuilder.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleUtil.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/PackageTranslator.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/RuntimeBeanEntry.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ServiceInterfaceEntry.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/TypeProviderWrapper.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/AbstractAttribute.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/AbstractDependencyAttribute.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/JavaAttribute.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/ListAttribute.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/SimpleTypeResolver.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/TOAttribute.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/Util.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/util/FullyQualifiedNameHelper.java
opendaylight/distribution/opendaylight-karaf/pom.xml
opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ComponentActivator.java
opendaylight/md-sal/model/model-flow-service/src/main/yang/node-config.yang [new file with mode: 0644]
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/raft/RaftActor.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/AbstractRaftActorBehavior.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Candidate.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Follower.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Leader.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/RaftActorBehavior.java
opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/RaftActorTest.java
opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/AbstractRaftActorBehaviorTest.java
opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/CandidateTest.java
opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/FollowerTest.java
opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/LeaderTest.java
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/md/sal/binding/data/ListProcessingAndOrderingTest.java
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/common/actor/AbstractUntypedPersistentActorWithMetering.java [new file with mode: 0644]
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NodeToNormalizedNodeBuilder.java [deleted file]
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NodeValueCodec.java [deleted file]
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToProtocolBufferNode.java [deleted file]
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/AugmentationIdentifierGenerator.java
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/NodeIdentifierFactory.java
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/util/EncoderDecoderUtil.java [deleted file]
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/cohort3pc/ThreePhaseCommitCohortMessages.java
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionChainMessages.java
opendaylight/md-sal/sal-clustering-commons/src/main/resources/Cohort.proto
opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/util/NormalizedNodeXmlConverterTest.java [deleted file]
opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/protobuff/messages/transaction/ShardTransactionChainMessagesTest.java
opendaylight/md-sal/sal-clustering-config/src/main/resources/initial/05-clustering.xml.conf
opendaylight/md-sal/sal-common-impl/src/test/java/org/opendaylight/controller/md/sal/common/impl/util/compat/DataNormalizerTest.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ClusterWrapper.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ClusterWrapperImpl.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataChangeListener.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerProxy.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DatastoreContext.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStore.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/Shard.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardCommitCoordinator.java [new file with mode: 0644]
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 [deleted file]
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/TransactionChainProxy.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionProxy.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/exceptions/NotInitializedException.java [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/identifiers/ShardIdentifier.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/identifiers/ShardTransactionIdentifier.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/AbortTransaction.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/AbortTransactionReply.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ActorInitialized.java [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ActorNotInitialized.java [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CanCommitTransaction.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CanCommitTransactionReply.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CommitTransaction.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CommitTransactionReply.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CreateTransactionChain.java [deleted file]
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CreateTransactionChainReply.java [deleted file]
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ForwardedCommitTransaction.java [deleted file]
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ForwardedReadyTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ReadyTransactionReply.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/DistributedOperationalDataStoreProviderModule.java
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 [deleted file]
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/DataChangeListenerTest.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreIntegrationTest.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreTest.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/ShardTestKit.java [new file with mode: 0644]
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 [deleted file]
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/identifiers/ShardIdentifierTest.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/InMemoryJournal.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/MockClusterWrapper.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/java/org/opendaylight/controller/md/cluster/datastore/model/CompositeModel.java
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/DOMConcurrentDataCommitCoordinator.java [new file with mode: 0644]
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/DOMDataCommitExecutor.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/jmx/CommitStatsMXBeanImpl.java
opendaylight/md-sal/sal-dom-broker/src/main/yang/opendaylight-dom-broker-impl.yang
opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMConcurrentDataCommitCoordinatorTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPointManagerTest.java
opendaylight/md-sal/sal-dom-xsql/src/main/java/org/opendaylight/controller/md/sal/dom/xsql/XSQLAdapter.java
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ChainedTransactionCommitImpl.java [new file with mode: 0644]
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/DOMStoreTransactionChainImpl.java [new file with mode: 0644]
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonToCompositeNodeReader.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/NormalizedNodeXmlBodyWriter.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/cnsn/test/JsonToCnSnTest.java
opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/invalid-uri-character-in-value.json [new file with mode: 0644]
opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/impl/ModelGenerator.java
opendaylight/md-sal/sal-rest-docgen/src/test/java/org/opendaylight/controller/sal/rest/doc/impl/ModelGeneratorTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-docgen/src/test/resources/yang/opflex.yang [new file with mode: 0644]
opendaylight/md-sal/sal-rest-docgen/src/test/resources/yang/toaster.yang
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/runtime/InstanceRuntime.java
opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/SubtreeFilter.java
opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/NetconfMonitoringServiceImplTest.java [new file with mode: 0644]
opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/SubtreeFilterTest.java
opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultCloseSessionTest.java [new file with mode: 0644]
opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultCommitTest.java [new file with mode: 0644]
opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultGetSchemaTest.java [new file with mode: 0644]
opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultStopExiTest.java [new file with mode: 0644]
opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/osgi/NetconfImplActivatorTest.java [new file with mode: 0644]
opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationServiceFactoryTrackerTest.java [new file with mode: 0644]
opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/util/DeserializerExceptionHandlerTest.java [new file with mode: 0644]
opendaylight/netconf/netconf-impl/src/test/resources/subtree/9/post-filter.xml [new file with mode: 0644]
opendaylight/netconf/netconf-impl/src/test/resources/subtree/9/pre-filter.xml [new file with mode: 0644]
opendaylight/netconf/netconf-impl/src/test/resources/subtree/9/request.xml [new file with mode: 0644]
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITSecureTest.java
opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringActivatorTest.java [new file with mode: 0644]
opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringOperationServiceTest.java [new file with mode: 0644]
opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringServiceTrackerTest.java [new file with mode: 0644]
opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/AsyncSshHandler.java
opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/AsyncSshHandlerReader.java [moved from opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/AsyncSshHanderReader.java with 66% similarity]
opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/AsyncSshHandlerWriter.java
opendaylight/netconf/netconf-netty-util/src/test/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/AsyncSshHandlerTest.java
opendaylight/netconf/netconf-ssh/pom.xml
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/RemoteNetconfCommand.java [new file with mode: 0644]
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SshProxyClientHandler.java [new file with mode: 0644]
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SshProxyServer.java [new file with mode: 0644]
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/AuthProviderTracker.java [new file with mode: 0644]
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/NetconfSSHActivator.java
opendaylight/netconf/netconf-testtool/pom.xml
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/DataList.java [new file with mode: 0644]
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/Main.java
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/NetconfDeviceSimulator.java
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedCommit.java [new file with mode: 0644]
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedEditConfig.java [new file with mode: 0644]
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedGet.java
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedGetConfig.java [new file with mode: 0644]
opendaylight/netconf/netconf-testtool/src/main/resources/org.ops4j.pax.url.mvn.cfg [new file with mode: 0644]
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlElement.java
opendaylight/netconf/pom.xml
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/action/Action.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/Match.java
opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/action/ActionTest.java
opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/match/MatchTest.java
opendaylight/switchmanager/implementation/src/main/java/org/opendaylight/controller/switchmanager/internal/Activator.java

index c324f6cea65cc4d9fb9e6883f43ff93d854c03c8..d7d8e0ddacfbbf851741dfe18312452606d4ecec 100644 (file)
@@ -80,6 +80,7 @@
    <feature name="odl-base-eclipselink-persistence" description="EclipseLink Persistence API" version="2.0.4.v201112161009">
       <bundle start="true">mvn:eclipselink/javax.persistence/2.0.4.v201112161009</bundle>
       <bundle start="true">mvn:eclipselink/javax.resource/1.5.0.v200906010428</bundle>
+      <bundle start="true">mvn:org.eclipse.persistence/org.eclipse.persistence.antlr/2.5.0</bundle>
       <bundle start="true">mvn:org.eclipse.persistence/org.eclipse.persistence.moxy/2.5.0</bundle>
       <bundle start="true">mvn:org.eclipse.persistence/org.eclipse.persistence.core/2.5.0</bundle>
    </feature>
index 03d6fed6055d74ba4845a93be457fd3761720aa9..b44fa11657346148c27eada449d0b1c5f433e426 100644 (file)
       Optional TODO: Remove TODO comments.
     -->
     <!-- test to validate features.xml -->
-    <dependency>
-      <groupId>org.opendaylight.yangtools</groupId>
-      <artifactId>features-test</artifactId>
-      <version>${yangtools.version}</version>
-      <scope>test</scope>
-    </dependency>
+   <!--FIXME BUG-2195 When running single feature tests for netconf connector, features including ssh proxy server always fail (this behavior does not appear when running karaf distro directly)-->
+    <!--<dependency>-->
+      <!--<groupId>org.opendaylight.yangtools</groupId>-->
+      <!--<artifactId>features-test</artifactId>-->
+      <!--<version>${yangtools.version}</version>-->
+      <!--<scope>test</scope>-->
+    <!--</dependency>-->
     <!-- dependency for opendaylight-karaf-empty for use by testing -->
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
index 77fad0a9f75ba76ab57863e7dcb3f7fa43b3e0bb..ffb9ef746da4118982b6ed61a715024491a00a72 100644 (file)
         <type>xml</type>
         <scope>runtime</scope>
       </dependency>
+    <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>features-netconf-connector</artifactId>
+        <version>${mdsal.version}</version>
+        <classifier>features</classifier>
+        <type>xml</type>
+        <scope>runtime</scope>
+    </dependency>
       <!-- JMH Benchmark dependencies -->
       <dependency>
         <groupId>org.openjdk.jmh</groupId>
index ea87afa48dedddfe20ef5430aa60d25ecc594c1a..98a2c2cca16cbc8c085e530af206aa497c9e5d49 100644 (file)
@@ -98,10 +98,8 @@ final class ReconnectPromise<S extends ProtocolSession<?>, L extends SessionList
                 return;
             }
 
-            // Check if initial connection was fully finished. If the session was dropped during negotiation, reconnect will not happen.
-            // Session can be dropped during negotiation on purpose by the client side and would make no sense to initiate reconnect
             if (promise.isInitialConnectFinished() == false) {
-                return;
+                LOG.debug("Connection to {} was dropped during negotiation, reattempting", promise.address);
             }
 
             LOG.debug("Reconnecting after connection to {} was dropped", promise.address);
index 63026e384c498ce12dca810c94886f9a562215d8..fc38888de30af0158d9b4d20fc7e6387d73767eb 100644 (file)
@@ -250,52 +250,6 @@ public class ServerTest {
         assertFalse(session.isSuccess());
     }
 
-    @Test
-    public void testNegotiationFailedNoReconnect() throws Exception {
-        final Promise<Boolean> p = new DefaultPromise<>(GlobalEventExecutor.INSTANCE);
-
-        this.dispatcher = getServerDispatcher(p);
-
-        this.server = this.dispatcher.createServer(this.serverAddress, new SessionListenerFactory<SimpleSessionListener>() {
-            @Override
-            public SimpleSessionListener getSessionListener() {
-                return new SimpleSessionListener();
-            }
-        });
-
-        this.server.get();
-
-        this.clientDispatcher = new SimpleDispatcher(new SessionNegotiatorFactory<SimpleMessage, SimpleSession, SimpleSessionListener>() {
-            @Override
-            public SessionNegotiator<SimpleSession> getSessionNegotiator(final SessionListenerFactory<SimpleSessionListener> factory,
-                                                                         final Channel channel, final Promise<SimpleSession> promise) {
-
-                return new SimpleSessionNegotiator(promise, channel) {
-                    @Override
-                    protected void startNegotiation() throws Exception {
-                        negotiationFailed(new IllegalStateException("Negotiation failed"));
-                    }
-                };
-            }
-        }, new DefaultPromise<SimpleSession>(GlobalEventExecutor.INSTANCE), eventLoopGroup);
-
-        final ReconnectStrategyFactory reconnectStrategyFactory = mock(ReconnectStrategyFactory.class);
-        final ReconnectStrategy reconnectStrategy = getMockedReconnectStrategy();
-        doReturn(reconnectStrategy).when(reconnectStrategyFactory).createReconnectStrategy();
-
-        this.clientDispatcher.createReconnectingClient(this.serverAddress,
-                reconnectStrategyFactory, new SessionListenerFactory<SimpleSessionListener>() {
-                    @Override
-                    public SimpleSessionListener getSessionListener() {
-                        return new SimpleSessionListener();
-                    }
-                });
-
-
-        // Only one strategy should be created for initial connect, no more = no reconnects
-        verify(reconnectStrategyFactory, times(1)).createReconnectStrategy();
-    }
-
     private SimpleDispatcher getClientDispatcher() {
         return new SimpleDispatcher(new SessionNegotiatorFactory<SimpleMessage, SimpleSession, SimpleSessionListener>() {
             @Override
index 5ad6e0da8d2bf8a29d8d403783e378c5ab950346..48aa6ae64667f502a39cb636ae319ef7617db478 100644 (file)
@@ -39,7 +39,7 @@ public final class IdentityAttributeRef {
 
     @Override
     public String toString() {
-        final StringBuffer sb = new StringBuffer("IdentityAttributeRef{");
+        final StringBuilder sb = new StringBuilder("IdentityAttributeRef{");
         sb.append("qNameOfIdentity='").append(qNameOfIdentity).append('\'');
         sb.append('}');
         return sb.toString();
index abb9f1ae9bf4d448c78bc795a74f0076b68de745..c23a0cbf69850f364113a93579e79d9dc952ae5c 100644 (file)
@@ -29,6 +29,8 @@ import java.util.Set;
  */
 @ThreadSafe
 public class ObjectNameUtil {
+    private ObjectNameUtil() {
+    }
 
     public static final String ON_DOMAIN = ConfigRegistryConstants.ON_DOMAIN;
     public static final String MODULE_FACTORY_NAME_KEY = "moduleFactoryName";
@@ -270,7 +272,7 @@ public class ObjectNameUtil {
     }
 
     public static Map<String, String> getAdditionalProperties(ObjectName on) {
-        Hashtable<String, String> keyPropertyList = on.getKeyPropertyList();
+        Map<String, String> keyPropertyList = on.getKeyPropertyList();
         Map<String, String> result = new HashMap<>();
         for (Entry<String, String> entry : keyPropertyList.entrySet()) {
             result.put(entry.getKey(), entry.getValue());
@@ -304,8 +306,8 @@ public class ObjectNameUtil {
 
     public static ObjectName createModulePattern(String moduleName,
                                                  String instanceName) {
-        moduleName = moduleName == null ? ON_WILDCARD : moduleName;
-        instanceName = instanceName == null ? ON_WILDCARD : instanceName;
+        String finalModuleName = moduleName == null ? ON_WILDCARD : moduleName;
+        String finalInstanceName = instanceName == null ? ON_WILDCARD : instanceName;
 
         // do not return object names containing transaction name
         ObjectName namePattern = ObjectNameUtil
@@ -313,34 +315,34 @@ public class ObjectNameUtil {
                         + ObjectNameUtil.TYPE_KEY + "="
                         + ObjectNameUtil.TYPE_MODULE + ","
                         + ObjectNameUtil.MODULE_FACTORY_NAME_KEY + "="
-                        + moduleName + "," + ""
-                        + ObjectNameUtil.INSTANCE_NAME_KEY + "=" + instanceName);
+                        + finalModuleName + "," + ""
+                        + ObjectNameUtil.INSTANCE_NAME_KEY + "=" + finalInstanceName);
         return namePattern;
     }
 
     public static ObjectName createModulePattern(String ifcName,
                                                  String instanceName, String transactionName) {
-        ifcName = ifcName == null ? ON_WILDCARD : ifcName;
-        instanceName = instanceName == null ? ON_WILDCARD : instanceName;
-        transactionName = transactionName == null ? ON_WILDCARD : transactionName;
+        String finalIfcName = ifcName == null ? ON_WILDCARD : ifcName;
+        String finalInstanceName = instanceName == null ? ON_WILDCARD : instanceName;
+        String finalTransactionName = transactionName == null ? ON_WILDCARD : transactionName;
 
         return ObjectNameUtil.createON(ObjectNameUtil.ON_DOMAIN
                 + ":type=Module," + ObjectNameUtil.MODULE_FACTORY_NAME_KEY
-                + "=" + ifcName + "," + ObjectNameUtil.INSTANCE_NAME_KEY + "="
-                + instanceName + "," + ObjectNameUtil.TRANSACTION_NAME_KEY
-                + "=" + transactionName);
+                + "=" + finalIfcName + "," + ObjectNameUtil.INSTANCE_NAME_KEY + "="
+                + finalInstanceName + "," + ObjectNameUtil.TRANSACTION_NAME_KEY
+                + "=" + finalTransactionName);
     }
 
     public static ObjectName createRuntimeBeanPattern(String moduleName,
                                                       String instanceName) {
-        moduleName = moduleName == null ? ON_WILDCARD : moduleName;
-        instanceName = instanceName == null ? ON_WILDCARD : instanceName;
+        String finalModuleName = moduleName == null ? ON_WILDCARD : moduleName;
+        String finalInstanceName = instanceName == null ? ON_WILDCARD : instanceName;
 
         return ObjectNameUtil.createON(ObjectNameUtil.ON_DOMAIN + ":"
                 + ObjectNameUtil.TYPE_KEY + "="
                 + ObjectNameUtil.TYPE_RUNTIME_BEAN + ","
-                + ObjectNameUtil.MODULE_FACTORY_NAME_KEY + "=" + moduleName
-                + "," + ObjectNameUtil.INSTANCE_NAME_KEY + "=" + instanceName
+                + ObjectNameUtil.MODULE_FACTORY_NAME_KEY + "=" + finalModuleName
+                + "," + ObjectNameUtil.INSTANCE_NAME_KEY + "=" + finalInstanceName
                 + ",*");
 
     }
index 1d9563bf4e1d7733b170cdd6c092f473a8baae20..bdb6f0e344e97472cb5d5e3e241783776d51066d 100644 (file)
@@ -12,6 +12,9 @@ import javax.management.ObjectName;
 
 public class ConfigRegistryConstants {
 
+    private ConfigRegistryConstants() {
+    }
+
     public static final String TYPE_CONFIG_REGISTRY = "ConfigRegistry";
 
     public static final String ON_DOMAIN = "org.opendaylight.controller";
index a0a4292adf406a597fa120cdbf869c5b4cc0e0c6..e46d327ece9aff4e89ecf7ab0088561acb17c5aa 100644 (file)
@@ -122,7 +122,9 @@ module config {
                  the actual service-type which is actually required.";
 
             mandatory true;
-            type service-type-ref;
+            type leafref {
+                path "/config:services/config:service/config:type";
+            }
         }
 
         leaf name {
@@ -138,7 +140,7 @@ module config {
             "Top level container encapsulating configuration of all modules.";
 
         list module {
-            key "name";
+            key "type name";
             leaf name {
                 description "Unique module instance name";
                 type string;
index b7cdf9475753e92f34fcbeae620a95025c9941a9..605223ae227cfa2b6e22e7861e63df325b17686b 100644 (file)
@@ -60,7 +60,7 @@ import java.util.Set;
  */
 @ThreadSafe
 public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBean {
-    private static final Logger logger = LoggerFactory.getLogger(ConfigRegistryImpl.class);
+    private static final Logger LOGGER = LoggerFactory.getLogger(ConfigRegistryImpl.class);
 
     private final ModuleFactoriesResolver resolver;
     private final MBeanServer configMBeanServer;
@@ -166,7 +166,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
         for (ModuleInternalInfo moduleInternalInfo : currentConfig.getEntries()) {
             String name = moduleInternalInfo.getModuleFactory().getImplementationName();
             if (allCurrentFactories.containsKey(name) == false) {
-                logger.trace("Factory {} not found in SR, using reference from previous commit", name);
+                LOGGER.trace("Factory {} not found in SR, using reference from previous commit", name);
                 allCurrentFactories.put(name,
                         Maps.immutableEntry(moduleInternalInfo.getModuleFactory(), moduleInternalInfo.getBundleContext()));
             }
@@ -202,7 +202,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
             throws ConflictingVersionException, ValidationException {
         final String transactionName = ObjectNameUtil
                 .getTransactionName(transactionControllerON);
-        logger.trace("About to commit {}. Current parentVersion: {}, versionCounter {}", transactionName, version, versionCounter);
+        LOGGER.trace("About to commit {}. Current parentVersion: {}, versionCounter {}", transactionName, version, versionCounter);
 
         // find ConfigTransactionController
         Map<String, Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>> transactions = transactionsHolder.getCurrentTransactions();
@@ -230,7 +230,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
         } catch (Error | RuntimeException t) { // some libs throw Errors: e.g.
             // javax.xml.ws.spi.FactoryFinder$ConfigurationError
             isHealthy = false;
-            logger.error("Configuration Transaction failed on 2PC, server is unhealthy", t);
+            LOGGER.error("Configuration Transaction failed on 2PC, server is unhealthy", t);
             if (t instanceof RuntimeException) {
                 throw (RuntimeException) t;
             } else {
@@ -292,7 +292,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
 
         int orderingIdx = 0;
         for (ModuleIdentifier moduleIdentifier : orderedModuleIdentifiers) {
-            logger.trace("Registering {}", moduleIdentifier);
+            LOGGER.trace("Registering {}", moduleIdentifier);
             ModuleInternalTransactionalInfo entry = commitInfo.getCommitted()
                     .get(moduleIdentifier);
             if (entry == null) {
@@ -427,7 +427,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
                 configTransactionControllerEntry.getValue().close();
                 configTransactionController.abortConfig();
             } catch (RuntimeException e) {
-                logger.warn("Ignoring exception while aborting {}",
+                LOGGER.warn("Ignoring exception while aborting {}",
                         configTransactionController, e);
             }
         }
@@ -524,14 +524,10 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
     @Override
     public Set<ObjectName> lookupRuntimeBeans(String moduleName,
                                               String instanceName) {
-        if (moduleName == null) {
-            moduleName = "*";
-        }
-        if (instanceName == null) {
-            instanceName = "*";
-        }
+        String finalModuleName = moduleName == null ? "*" : moduleName;
+        String finalInstanceName = instanceName == null ? "*" : instanceName;
         ObjectName namePattern = ObjectNameUtil.createRuntimeBeanPattern(
-                moduleName, instanceName);
+                finalModuleName, finalInstanceName);
         return baseJMXRegistrator.queryNames(namePattern, null);
     }
 
@@ -609,7 +605,7 @@ class ConfigHolder {
      * Service Registry.
      */
     public void addAll(Collection<ModuleInternalInfo> configInfos) {
-        if (currentConfig.size() > 0) {
+        if (!currentConfig.isEmpty()) {
             throw new IllegalStateException(
                     "Error - some config entries were not removed: "
                             + currentConfig);
index 39eef8741ba840309b8293e19f14af437652e82e..a58f7a05c65ae9a1f31a407e53c6f54d028e3200 100644 (file)
@@ -53,7 +53,7 @@ class ConfigTransactionControllerImpl implements
         ConfigTransactionControllerInternal,
         ConfigTransactionControllerImplMXBean,
         Identifiable<TransactionIdentifier> {
-    private static final Logger logger = LoggerFactory.getLogger(ConfigTransactionControllerImpl.class);
+    private static final Logger LOGGER = LoggerFactory.getLogger(ConfigTransactionControllerImpl.class);
 
     private final ConfigTransactionLookupRegistry txLookupRegistry;
     private final ObjectName controllerON;
@@ -226,7 +226,7 @@ class ConfigTransactionControllerImpl implements
             boolean isDefaultBean, BundleContext bundleContext)
             throws InstanceAlreadyExistsException {
 
-        logger.debug("Adding module {} to transaction {}", moduleIdentifier, this);
+        LOGGER.debug("Adding module {} to transaction {}", moduleIdentifier, this);
         if (moduleIdentifier.equals(module.getIdentifier()) == false) {
             throw new IllegalStateException("Incorrect name reported by module. Expected "
                     + moduleIdentifier + ", got " + module.getIdentifier());
@@ -271,15 +271,13 @@ class ConfigTransactionControllerImpl implements
     }
 
     private synchronized void destroyModule(ModuleIdentifier moduleIdentifier) {
-        logger.debug("Destroying module {} in transaction {}", moduleIdentifier, this);
+        LOGGER.debug("Destroying module {} in transaction {}", moduleIdentifier, this);
         transactionStatus.checkNotAborted();
 
         ModuleInternalTransactionalInfo found = dependencyResolverManager.findModuleInternalTransactionalInfo(moduleIdentifier);
-        if (blankTransaction == false) {
-
-            if (found.isDefaultBean()) {
-                logger.warn("Warning: removing default bean. This will be forbidden in next version of config-subsystem");
-            }
+        if (blankTransaction == false &&
+                found.isDefaultBean()) {
+            LOGGER.warn("Warning: removing default bean. This will be forbidden in next version of config-subsystem");
         }
         // first remove refNames, it checks for objectname existence
 
@@ -287,7 +285,7 @@ class ConfigTransactionControllerImpl implements
             writableSRRegistry.removeServiceReferences(
                     ObjectNameUtil.createTransactionModuleON(getTransactionName(), moduleIdentifier));
         } catch (InstanceNotFoundException e) {
-            logger.error("Possible code error: cannot find {} in {}", moduleIdentifier, writableSRRegistry);
+            LOGGER.error("Possible code error: cannot find {} in {}", moduleIdentifier, writableSRRegistry);
             throw new IllegalStateException("Possible code error: cannot find " + moduleIdentifier, e);
         }
 
@@ -313,15 +311,15 @@ class ConfigTransactionControllerImpl implements
         }
         configBeanModificationDisabled.set(true);
         try {
-            validate_noLocks();
+            validateNoLocks();
         } finally {
             configBeanModificationDisabled.set(false);
         }
     }
 
-    private void validate_noLocks() throws ValidationException {
+    private void validateNoLocks() throws ValidationException {
         transactionStatus.checkNotAborted();
-        logger.trace("Validating transaction {}", getTransactionIdentifier());
+        LOGGER.trace("Validating transaction {}", getTransactionIdentifier());
         // call validate()
         List<ValidationException> collectedExceptions = new ArrayList<>();
         for (Entry<ModuleIdentifier, Module> entry : dependencyResolverManager
@@ -331,17 +329,17 @@ class ConfigTransactionControllerImpl implements
             try {
                 module.validate();
             } catch (Exception e) {
-                logger.warn("Validation exception in {}", getTransactionName(),
+                LOGGER.warn("Validation exception in {}", getTransactionName(),
                         e);
                 collectedExceptions.add(ValidationException
                         .createForSingleException(name, e));
             }
         }
-        if (collectedExceptions.size() > 0) {
+        if (!collectedExceptions.isEmpty()) {
             throw ValidationException
                     .createFromCollectedValidationExceptions(collectedExceptions);
         }
-        logger.trace("Validated transaction {}", getTransactionIdentifier());
+        LOGGER.trace("Validated transaction {}", getTransactionIdentifier());
     }
 
     /**
@@ -358,9 +356,9 @@ class ConfigTransactionControllerImpl implements
         transactionStatus.checkNotCommitStarted();
         configBeanModificationDisabled.set(true);
         try {
-            validate_noLocks();
+            validateNoLocks();
         } catch (ValidationException e) {
-            logger.trace("Commit failed on validation");
+            LOGGER.trace("Commit failed on validation");
             configBeanModificationDisabled.set(false); // recoverable error
             throw e;
         }
@@ -383,7 +381,7 @@ class ConfigTransactionControllerImpl implements
                             + "to obtain a lock");
         }
 
-        logger.trace("Committing transaction {}", getTransactionIdentifier());
+        LOGGER.trace("Committing transaction {}", getTransactionIdentifier());
 
         // call getInstance()
         for (Entry<ModuleIdentifier, Module> entry : dependencyResolverManager
@@ -391,12 +389,12 @@ class ConfigTransactionControllerImpl implements
             Module module = entry.getValue();
             ModuleIdentifier name = entry.getKey();
             try {
-                logger.debug("About to commit {} in transaction {}",
+                LOGGER.debug("About to commit {} in transaction {}",
                         name, getTransactionIdentifier());
                 AutoCloseable instance = module.getInstance();
                 checkNotNull(instance, "Instance is null:{} in transaction {}", name, getTransactionIdentifier());
             } catch (Exception e) {
-                logger.error("Commit failed on {} in transaction {}", name,
+                LOGGER.error("Commit failed on {} in transaction {}", name,
                         getTransactionIdentifier(), e);
                 internalAbort();
                 throw new IllegalStateException(
@@ -407,7 +405,7 @@ class ConfigTransactionControllerImpl implements
 
         // count dependency order
 
-        logger.trace("Committed configuration {}", getTransactionIdentifier());
+        LOGGER.trace("Committed configuration {}", getTransactionIdentifier());
         transactionStatus.setCommitted();
 
         return dependencyResolverManager.getSortedModuleIdentifiers();
@@ -421,7 +419,7 @@ class ConfigTransactionControllerImpl implements
     }
 
     private void internalAbort() {
-        logger.trace("Aborting {}", this);
+        LOGGER.trace("Aborting {}", this);
         transactionStatus.setAborted();
         close();
     }
index d34a739703e8f8eba7d60a90ca6fa713a301f802..b59b48e5a98eafb05d92622e1b1d9363c81f91a0 100644 (file)
@@ -11,7 +11,7 @@ import java.util.LinkedList;
 import java.util.concurrent.TimeUnit;
 
 public class DeadlockMonitor implements AutoCloseable {
-    private static final Logger logger = LoggerFactory.getLogger(DeadlockMonitorRunnable.class);
+    private static final Logger LOGGER = LoggerFactory.getLogger(DeadlockMonitorRunnable.class);
 
     private static final long WARN_AFTER_MILLIS = 5000;
 
@@ -43,7 +43,7 @@ public class DeadlockMonitor implements AutoCloseable {
             moduleIdentifierWithNanosStack.push(current);
             top = current;
         }
-        logger.trace("setCurrentlyInstantiatedModule {}, top {}", currentlyInstantiatedModule, top);
+        LOGGER.trace("setCurrentlyInstantiatedModule {}, top {}", currentlyInstantiatedModule, top);
     }
 
     public boolean isAlive() {
@@ -78,7 +78,7 @@ public class DeadlockMonitor implements AutoCloseable {
                     // is the getInstance() running longer than WARN_AFTER_MILLIS ?
                     long runningTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - copy.nanoTime);
                     if (runningTime > WARN_AFTER_MILLIS) {
-                        logger.warn("{} did not finish after {} ms", copy.moduleIdentifier, runningTime);
+                        LOGGER.warn("{} did not finish after {} ms", copy.moduleIdentifier, runningTime);
                     }
                 }
                 try {
@@ -87,7 +87,7 @@ public class DeadlockMonitor implements AutoCloseable {
                     interrupt();
                 }
             }
-            logger.trace("Exiting {}", this);
+            LOGGER.trace("Exiting {}", this);
         }
 
         @Override
@@ -122,14 +122,21 @@ public class DeadlockMonitor implements AutoCloseable {
 
         @Override
         public boolean equals(Object o) {
-            if (this == o) return true;
-            if (o == null || getClass() != o.getClass()) return false;
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
 
             ModuleIdentifierWithNanos that = (ModuleIdentifierWithNanos) o;
 
-            if (nanoTime != that.nanoTime) return false;
-            if (moduleIdentifier != null ? !moduleIdentifier.equals(that.moduleIdentifier) : that.moduleIdentifier != null)
+            if (nanoTime != that.nanoTime) {
                 return false;
+            }
+            if (moduleIdentifier != null ? !moduleIdentifier.equals(that.moduleIdentifier) : that.moduleIdentifier != null) {
+                return false;
+            }
 
             return true;
         }
index 52bb3f5ed1df99a678e9ad44357cef6eadc4b3cf..0f881e95add37a0ac925ff1b835ba2813cc6c4b0 100644 (file)
@@ -38,7 +38,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceReadableRegistry, SearchableServiceReferenceWritableRegistry {
-    private static final Logger logger = LoggerFactory.getLogger(ServiceReferenceRegistryImpl.class);
+    private static final Logger LOGGER = LoggerFactory.getLogger(ServiceReferenceRegistryImpl.class);
 
     private final Map<String, ModuleFactory> factories;
     private final Map<String, Set<String>> factoryNamesToQNames;
@@ -176,7 +176,7 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe
                 boolean skipChecks = true;
                 newRegistry.saveServiceReference(refNameEntry.getKey(), currentImplementation, skipChecks);
             } catch (InstanceNotFoundException e) {
-                logger.error("Cannot save service reference({}, {})", refNameEntry.getKey(), currentImplementation);
+                LOGGER.error("Cannot save service reference({}, {})", refNameEntry.getKey(), currentImplementation);
                 throw new IllegalStateException("Possible code error", e);
             }
         }
@@ -201,22 +201,22 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe
 
         Map<String, Set<String /* QName */>> modifiableFactoryNamesToQNames = new HashMap<>();
         Set<ServiceInterfaceAnnotation> allAnnotations = new HashSet<>();
-        Set<String /* qName */> allQNames = new HashSet<>();
+        Set<String /* qName */> allQNameSet = new HashSet<>();
 
 
         for (Entry<String, ModuleFactory> entry : factories.entrySet()) {
             if (entry.getKey().equals(entry.getValue().getImplementationName()) == false) {
-                logger.error("Possible error in code: Mismatch between supplied and actual name of {}", entry);
+                LOGGER.error("Possible error in code: Mismatch between supplied and actual name of {}", entry);
                 throw new IllegalArgumentException("Possible error in code: Mismatch between supplied and actual name of " + entry);
             }
             Set<ServiceInterfaceAnnotation> siAnnotations = InterfacesHelper.getServiceInterfaceAnnotations(entry.getValue());
             Set<String> qNames = InterfacesHelper.getQNames(siAnnotations);
             allAnnotations.addAll(siAnnotations);
-            allQNames.addAll(qNames);
+            allQNameSet.addAll(qNames);
             modifiableFactoryNamesToQNames.put(entry.getKey(), Collections.unmodifiableSet(qNames));
         }
         this.factoryNamesToQNames = Collections.unmodifiableMap(modifiableFactoryNamesToQNames);
-        this.allQNames = Collections.unmodifiableSet(allQNames);
+        this.allQNames = Collections.unmodifiableSet(allQNameSet);
         // fill namespacesToAnnotations
         Map<String /* namespace */, Map<String /* localName */, ServiceInterfaceAnnotation>> modifiableNamespacesToAnnotations =
                 new HashMap<>();
@@ -228,7 +228,7 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe
                 modifiableNamespacesToAnnotations.put(sia.namespace(), ofNamespace);
             }
             if (ofNamespace.containsKey(sia.localName())) {
-                logger.error("Cannot construct namespacesToAnnotations map, conflict between local names in {}, offending local name: {}, map so far {}",
+                LOGGER.error("Cannot construct namespacesToAnnotations map, conflict between local names in {}, offending local name: {}, map so far {}",
                         sia.namespace(), sia.localName(), modifiableNamespacesToAnnotations);
                 throw new IllegalArgumentException("Conflict between local names in " + sia.namespace() + " : " + sia.localName());
             }
@@ -237,7 +237,7 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe
         }
         this.namespacesToAnnotations = Collections.unmodifiableMap(modifiableNamespacesToAnnotations);
         this.serviceQNamesToAnnotations = Collections.unmodifiableMap(modifiableServiceQNamesToAnnotations);
-        logger.trace("factoryNamesToQNames:{}", this.factoryNamesToQNames);
+        LOGGER.trace("factoryNamesToQNames:{}", this.factoryNamesToQNames);
     }
 
     @Override
@@ -256,7 +256,7 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe
         String factoryName = ObjectNameUtil.getFactoryName(objectName);
         Set<String> serviceInterfaceAnnotations = factoryNamesToQNames.get(factoryName);
         if (serviceInterfaceAnnotations == null) {
-            logger.error("Possible error in code: cannot find factory annotations of '{}' extracted from ON {} in {}",
+            LOGGER.error("Possible error in code: cannot find factory annotations of '{}' extracted from ON {} in {}",
                     factoryName, objectName, factoryNamesToQNames);
             throw new IllegalArgumentException("Cannot find factory with name " + factoryName);
         }
@@ -267,12 +267,12 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe
     public synchronized String getServiceInterfaceName(String namespace, String localName) {
         Map<String /* localName */, ServiceInterfaceAnnotation> ofNamespace = namespacesToAnnotations.get(namespace);
         if (ofNamespace == null) {
-            logger.error("Cannot find namespace {} in {}", namespace, namespacesToAnnotations);
+            LOGGER.error("Cannot find namespace {} in {}", namespace, namespacesToAnnotations);
             throw new IllegalArgumentException("Cannot find namespace " + namespace);
         }
         ServiceInterfaceAnnotation sia = ofNamespace.get(localName);
         if (sia == null) {
-            logger.error("Cannot find local name {} in namespace {}, found only {}", localName, namespace, ofNamespace);
+            LOGGER.error("Cannot find local name {} in namespace {}, found only {}", localName, namespace, ofNamespace);
             throw new IllegalArgumentException("Cannot find local name " + localName + " in namespace " + namespace);
         }
         return sia.value();
@@ -300,7 +300,7 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe
         try {
             on = lookupRegistry.lookupConfigBean(moduleIdentifier.getFactoryName(), moduleIdentifier.getInstanceName());
         } catch (InstanceNotFoundException e) {
-            logger.error("Cannot find instance {}", moduleIdentifier);
+            LOGGER.error("Cannot find instance {}", moduleIdentifier);
             throw new IllegalStateException("Cannot find instance " + moduleIdentifier, e);
         }
         return on;
@@ -311,7 +311,7 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe
         ServiceReference serviceReference = new ServiceReference(serviceInterfaceQName, refName);
         ModuleIdentifier moduleIdentifier = refNames.get(serviceReference);
         if (moduleIdentifier == null) {
-            logger.error("Cannot find qname {} and refName {} in {}", serviceInterfaceQName, refName, refName);
+            LOGGER.error("Cannot find qname {} and refName {} in {}", serviceInterfaceQName, refName, refName);
             throw new IllegalArgumentException("Cannot find " + serviceReference);
         }
         return getObjectName(moduleIdentifier);
@@ -322,7 +322,7 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe
         Map<String, Map<String, ObjectName>> serviceMapping = getServiceMapping();
         Map<String, ObjectName> innerMap = serviceMapping.get(serviceInterfaceQName);
         if (innerMap == null) {
-            logger.error("Cannot find qname {} in {}", serviceInterfaceQName, refNames);
+            LOGGER.error("Cannot find qname {} in {}", serviceInterfaceQName, refNames);
             throw new IllegalArgumentException("Cannot find " + serviceInterfaceQName);
         }
         return innerMap;
@@ -348,7 +348,7 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe
         String referenceName = ObjectNameUtil.getReferenceName(objectName);
         ServiceReference serviceReference = new ServiceReference(serviceQName, referenceName);
         if (refNames.containsKey(serviceReference) == false) {
-            logger.warn("Cannot find {} in {}", serviceReference, refNames);
+            LOGGER.warn("Cannot find {} in {}", serviceReference, refNames);
             throw new InstanceNotFoundException("Service reference not found:" + objectName);
         }
     }
@@ -387,13 +387,13 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe
         // check that service interface name exist
         Set<String> serviceInterfaceQNames = factoryNamesToQNames.get(moduleIdentifier.getFactoryName());
         if (serviceInterfaceQNames == null) {
-            logger.error("Possible error in code: cannot find factoryName {} in {}, {}", moduleIdentifier.getFactoryName(),
+            LOGGER.error("Possible error in code: cannot find factoryName {} in {}, {}", moduleIdentifier.getFactoryName(),
                     factoryNamesToQNames, moduleIdentifier);
             throw new IllegalStateException("Possible error in code: cannot find annotations of existing factory " + moduleIdentifier.getFactoryName());
         }
         // supplied serviceInterfaceName must exist in this collection
         if (serviceInterfaceQNames.contains(serviceReference.getServiceInterfaceQName()) == false) {
-            logger.error("Cannot find qName {} with factory name {}, found {}", serviceReference.getServiceInterfaceQName(), moduleIdentifier.getFactoryName(), serviceInterfaceQNames);
+            LOGGER.error("Cannot find qName {} with factory name {}, found {}", serviceReference.getServiceInterfaceQName(), moduleIdentifier.getFactoryName(), serviceInterfaceQNames);
             throw new IllegalArgumentException("Cannot find service interface " + serviceReference.getServiceInterfaceQName() + " within factory " + moduleIdentifier.getFactoryName());
         }
 
@@ -465,11 +465,11 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe
     }
 
     private synchronized void removeServiceReference(ServiceReference serviceReference) throws InstanceNotFoundException {
-        logger.debug("Removing service reference {} from {}", serviceReference, this);
+        LOGGER.debug("Removing service reference {} from {}", serviceReference, this);
         assertWritable();
         // is the qName known?
         if (allQNames.contains(serviceReference.getServiceInterfaceQName()) == false) {
-            logger.error("Cannot find qname {} in {}", serviceReference.getServiceInterfaceQName(), allQNames);
+            LOGGER.error("Cannot find qname {} in {}", serviceReference.getServiceInterfaceQName(), allQNames);
             throw new IllegalArgumentException("Cannot find service interface " + serviceReference.getServiceInterfaceQName());
         }
         ModuleIdentifier removed = refNames.remove(serviceReference);
@@ -518,7 +518,7 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe
     private Set<ServiceReference> findServiceReferencesLinkingTo(ObjectName moduleObjectName, Set<String> serviceInterfaceQNames) {
         String factoryName = ObjectNameUtil.getFactoryName(moduleObjectName);
         if (serviceInterfaceQNames == null) {
-            logger.warn("Possible error in code: cannot find factoryName {} in {}, object name {}", factoryName, factoryNamesToQNames, moduleObjectName);
+            LOGGER.warn("Possible error in code: cannot find factoryName {} in {}, object name {}", factoryName, factoryNamesToQNames, moduleObjectName);
             throw new IllegalStateException("Possible error in code: cannot find annotations of existing factory " + factoryName);
         }
         String instanceName = ObjectNameUtil.getInstanceName(moduleObjectName);
index 4f60a673f5f711ce17815061318f2641bbda0091..a7a67d3d16c734267fd123472880dc598e5f0b28 100644 (file)
@@ -45,7 +45,7 @@ import org.slf4j.LoggerFactory;
  */
 final class DependencyResolverImpl implements DependencyResolver,
         Comparable<DependencyResolverImpl> {
-    private static final Logger logger = LoggerFactory.getLogger(DependencyResolverImpl.class);
+    private static final Logger LOGGER = LoggerFactory.getLogger(DependencyResolverImpl.class);
 
     private final ModulesHolder modulesHolder;
     private final ModuleIdentifier name;
@@ -107,9 +107,9 @@ final class DependencyResolverImpl implements DependencyResolver,
                 ), jmxAttribute
         );
 
-        dependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON);
+        ObjectName newDependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON);
 
-        ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(dependentReadOnlyON, ObjectNameUtil
+        ModuleIdentifier moduleIdentifier = ObjectNameUtil.fromON(newDependentReadOnlyON, ObjectNameUtil
                 .TYPE_MODULE);
 
         ModuleFactory foundFactory = modulesHolder.findModuleFactory(moduleIdentifier, jmxAttribute);
@@ -122,7 +122,7 @@ final class DependencyResolverImpl implements DependencyResolver,
                             + "Module name is %s : %s, expected service interface %s, dependent module ON %s , "
                             + "attribute %s",
                     foundFactory.getImplementationName(), foundFactory,
-                    expectedServiceInterface, dependentReadOnlyON,
+                    expectedServiceInterface, newDependentReadOnlyON,
                     jmxAttribute
             );
             throw new JmxAttributeValidationException(message, jmxAttribute);
@@ -134,13 +134,14 @@ final class DependencyResolverImpl implements DependencyResolver,
 
     // translate from serviceref to module ON
     private ObjectName translateServiceRefIfPossible(ObjectName dependentReadOnlyON) {
-        if (ObjectNameUtil.isServiceReference(dependentReadOnlyON)) {
-            String serviceQName = ObjectNameUtil.getServiceQName(dependentReadOnlyON);
-            String refName = ObjectNameUtil.getReferenceName(dependentReadOnlyON);
-            dependentReadOnlyON = ObjectNameUtil.withoutTransactionName( // strip again of transaction name
+        ObjectName translatedDependentReadOnlyON = dependentReadOnlyON;
+        if (ObjectNameUtil.isServiceReference(translatedDependentReadOnlyON)) {
+            String serviceQName = ObjectNameUtil.getServiceQName(translatedDependentReadOnlyON);
+            String refName = ObjectNameUtil.getReferenceName(translatedDependentReadOnlyON);
+            translatedDependentReadOnlyON = ObjectNameUtil.withoutTransactionName( // strip again of transaction name
                     readableRegistry.lookupConfigBeanByServiceInterfaceName(serviceQName, refName));
         }
-        return dependentReadOnlyON;
+        return translatedDependentReadOnlyON;
     }
 
     /**
@@ -155,12 +156,12 @@ final class DependencyResolverImpl implements DependencyResolver,
                     "Null parameters not allowed, got %s %s %s", expectedType,
                     dependentReadOnlyON, jmxAttribute));
         }
-        dependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON);
+        ObjectName translatedDependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON);
         transactionStatus.checkCommitStarted();
         transactionStatus.checkNotCommitted();
 
         ModuleIdentifier dependentModuleIdentifier = ObjectNameUtil.fromON(
-                dependentReadOnlyON, ObjectNameUtil.TYPE_MODULE);
+                translatedDependentReadOnlyON, ObjectNameUtil.TYPE_MODULE);
         Module module = modulesHolder.findModule(dependentModuleIdentifier,
                 jmxAttribute);
         synchronized (this) {
@@ -199,7 +200,7 @@ final class DependencyResolverImpl implements DependencyResolver,
         if (expectedBaseClass.isAssignableFrom(deserialized)) {
             return (Class<T>) deserialized;
         } else {
-            logger.error("Cannot resolve class of identity {} : deserialized class {} is not a subclass of {}.",
+            LOGGER.error("Cannot resolve class of identity {} : deserialized class {} is not a subclass of {}.",
                     identityRef, deserialized, expectedBaseClass);
             throw new IllegalArgumentException("Deserialized identity " + deserialized + " cannot be cast to " + expectedBaseClass);
         }
@@ -277,17 +278,17 @@ final class DependencyResolverImpl implements DependencyResolver,
     @Override
     public Object getAttribute(ObjectName name, String attribute)
             throws MBeanException, AttributeNotFoundException, InstanceNotFoundException, ReflectionException {
-        name = translateServiceRefIfPossible(name);
+        ObjectName newName = translateServiceRefIfPossible(name);
         // add transaction name
-        name = ObjectNameUtil.withTransactionName(name, transactionName);
-        return mBeanServer.getAttribute(name, attribute);
+        newName = ObjectNameUtil.withTransactionName(newName, transactionName);
+        return mBeanServer.getAttribute(newName, attribute);
     }
 
     @Override
     public <T> T newMXBeanProxy(ObjectName name, Class<T> interfaceClass) {
-        name = translateServiceRefIfPossible(name);
+        ObjectName newName = translateServiceRefIfPossible(name);
         // add transaction name
-        name = ObjectNameUtil.withTransactionName(name, transactionName);
-        return JMX.newMXBeanProxy(mBeanServer, name, interfaceClass);
+        newName = ObjectNameUtil.withTransactionName(newName, transactionName);
+        return JMX.newMXBeanProxy(mBeanServer, newName, interfaceClass);
     }
 }
index 2a1a908e7a18875c1baed6997fe9a6e5f6848519..15f5d48a6f51f43decd567129ce5d0854cc9ddcb 100644 (file)
@@ -139,7 +139,7 @@ public class DependencyResolverManager implements DependencyResolverFactory, Aut
 
             @Override
             protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
-                boolean isGetInstance = method.getName().equals("getInstance");
+                boolean isGetInstance = "getInstance".equals(method.getName());
                 if (isGetInstance) {
                     if (cachedInstance != null) {
                         return cachedInstance;
index 2aa74758d47c6fd2c7cc6b1fa095695ea8e91ded..ec2418bc6c902749ba72896aeb3924e62dac381e 100644 (file)
@@ -22,7 +22,7 @@ import org.slf4j.LoggerFactory;
  */
 public class DestroyedModule implements AutoCloseable,
         Comparable<DestroyedModule>, Identifiable<ModuleIdentifier> {
-    private static final Logger logger = LoggerFactory
+    private static final Logger LOGGER = LoggerFactory
             .getLogger(DestroyedModule.class);
 
     private final ModuleIdentifier identifier;
@@ -43,21 +43,21 @@ public class DestroyedModule implements AutoCloseable,
 
     @Override
     public void close() {
-        logger.trace("Destroying {}", identifier);
+        LOGGER.trace("Destroying {}", identifier);
         try {
             instance.close();
         } catch (Exception e) {
-            logger.error("Error while closing instance of {}", identifier, e);
+            LOGGER.error("Error while closing instance of {}", identifier, e);
         }
         try {
             oldJMXRegistrator.close();
         } catch (Exception e) {
-            logger.error("Error while closing jmx registrator of {}", identifier, e);
+            LOGGER.error("Error while closing jmx registrator of {}", identifier, e);
         }
         try {
             osgiRegistration.close();
         } catch (Exception e) {
-            logger.error("Error while closing osgi registration of {}", identifier, e);
+            LOGGER.error("Error while closing osgi registration of {}", identifier, e);
         }
     }
 
index 7e48af1caae9adc31cb0c76b64a86d0fb7bca428..4a148669b16eaabaf076d41f7f89e56e6169786c 100644 (file)
@@ -57,7 +57,7 @@ import static java.lang.String.format;
  * a read only wrapper.
  */
 abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper {
-    private static final Logger logger = LoggerFactory
+    private static final Logger LOGGER = LoggerFactory
             .getLogger(AbstractDynamicWrapper.class);
 
     protected final boolean writable;
@@ -234,7 +234,7 @@ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper {
     public Object getAttribute(String attributeName)
             throws AttributeNotFoundException, MBeanException,
             ReflectionException {
-        if (attributeName.equals("MBeanInfo")) {
+        if ("MBeanInfo".equals(attributeName)) {
             return getMBeanInfo();
         }
 
@@ -318,7 +318,7 @@ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper {
                 result.add(new Attribute(attributeName, value));
 
             } catch (Exception e) {
-                logger.debug("Getting attribute {} failed", attributeName, e);
+                LOGGER.debug("Getting attribute {} failed", attributeName, e);
             }
         }
         return result;
@@ -342,7 +342,7 @@ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper {
                 && signature[0].equals(AttributeList.class.getName())) {
             return setAttributes((AttributeList) params[0]);
         } else {
-            logger.debug("Operation not found {} ", actionName);
+            LOGGER.debug("Operation not found {} ", actionName);
             throw new UnsupportedOperationException(
                     format("Operation not found on %s. Method invoke is only supported for getInstance and getAttribute(s) "
                             + "method, got actionName %s, params %s, signature %s ",
index f3e1b4e705c3b943230d13ee52eca44bd798b930..c4dee3513d6e5bedd9376ddf64f6405c0c76647b 100644 (file)
@@ -17,6 +17,9 @@ import java.util.Set;
 
 public class AnnotationsHelper {
 
+    private AnnotationsHelper() {
+    }
+
     /**
      * Look for annotation specified by annotationType on method. First observe
      * method's class, then its super classes, then all provided interfaces.
index 044f7a9ada06af871fad5bc1cad531e550bab8c8..14be2545047a87af8b1e514d0b81632cd3d71c06 100644 (file)
@@ -136,7 +136,7 @@ class AttributeHolder {
         for (RequireInterface ri : foundRequireInterfaces) {
             foundValues.add(ri.value());
         }
-        if (foundValues.size() == 0) {
+        if (foundValues.isEmpty()) {
             return null;
         } else if (foundValues.size() > 1) {
             throw new IllegalStateException("Error finding @RequireInterface. "
index 3a24940a4c058ba91155dcd15ca42e3a86443b4c..7d3cb277fb2405cf59b81a9b73d0896575eac0c7 100644 (file)
@@ -68,7 +68,7 @@ public class DynamicReadableWrapper extends AbstractDynamicWrapper implements
     public Object getAttribute(String attributeName)
             throws AttributeNotFoundException, MBeanException,
             ReflectionException {
-        if (attributeName.equals("getInstance")) {
+        if ("getInstance".equals(attributeName)) {
             return getInstance();
         }
         return super.getAttribute(attributeName);
index 07bd63b7c7be8c78397b227ae40db7e53cb8da91..c3885150d572f80d1000320678424e597d2558ce 100644 (file)
@@ -47,7 +47,7 @@ import java.lang.reflect.Method;
  */
 @ThreadSafe
 public class DynamicWritableWrapper extends AbstractDynamicWrapper {
-    private static final Logger logger = LoggerFactory
+    private static final Logger LOGGER = LoggerFactory
             .getLogger(DynamicWritableWrapper.class);
 
     private final ReadOnlyAtomicBoolean configBeanModificationDisabled;
@@ -77,23 +77,24 @@ public class DynamicWritableWrapper extends AbstractDynamicWrapper {
     @Override
     public synchronized void setAttribute(Attribute attribute)
             throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException {
+        Attribute newAttribute = attribute;
         if (configBeanModificationDisabled.get() == true) {
             throw new IllegalStateException("Operation is not allowed now");
         }
 
-        if (attribute.getName().equals("Attribute")) {
-            setAttribute((Attribute) attribute.getValue());
+        if ("Attribute".equals(newAttribute.getName())) {
+            setAttribute((Attribute) newAttribute.getValue());
             return;
         }
 
         try {
-            if (attribute.getValue() instanceof ObjectName) {
-                attribute = fixDependencyAttribute(attribute);
-            } else if (attribute.getValue() instanceof ObjectName[]) {
-                attribute = fixDependencyListAttribute(attribute);
+            if (newAttribute.getValue() instanceof ObjectName) {
+                newAttribute = fixDependencyAttribute(newAttribute);
+            } else if (newAttribute.getValue() instanceof ObjectName[]) {
+                newAttribute = fixDependencyListAttribute(newAttribute);
             }
 
-            internalServer.setAttribute(objectNameInternal, attribute);
+            internalServer.setAttribute(objectNameInternal, newAttribute);
         } catch (InstanceNotFoundException e) {
             throw new MBeanException(e);
         }
@@ -101,21 +102,23 @@ public class DynamicWritableWrapper extends AbstractDynamicWrapper {
     }
 
     private Attribute fixDependencyListAttribute(Attribute attribute) {
-        AttributeHolder attributeHolder = attributeHolderMap.get(attribute.getName());
+        Attribute newAttribute = attribute;
+        AttributeHolder attributeHolder = attributeHolderMap.get(newAttribute.getName());
         if (attributeHolder.getRequireInterfaceOrNull() != null) {
-            attribute = new Attribute(attribute.getName(), fixObjectNames((ObjectName[]) attribute.getValue()));
+            newAttribute = new Attribute(newAttribute.getName(), fixObjectNames((ObjectName[]) newAttribute.getValue()));
         }
-        return attribute;
+        return newAttribute;
     }
 
     private Attribute fixDependencyAttribute(Attribute attribute) {
-        AttributeHolder attributeHolder = attributeHolderMap.get(attribute.getName());
+        Attribute newAttribute = attribute;
+        AttributeHolder attributeHolder = attributeHolderMap.get(newAttribute.getName());
         if (attributeHolder.getRequireInterfaceOrNull() != null) {
-            attribute = new Attribute(attribute.getName(), fixObjectName((ObjectName) attribute.getValue()));
+            newAttribute = new Attribute(newAttribute.getName(), fixObjectName((ObjectName) newAttribute.getValue()));
         } else {
-            attribute = new Attribute(attribute.getName(), attribute.getValue());
+            newAttribute = new Attribute(newAttribute.getName(), newAttribute.getValue());
         }
-        return attribute;
+        return newAttribute;
     }
 
     private ObjectName[] fixObjectNames(ObjectName[] dependencies) {
@@ -137,7 +140,7 @@ public class DynamicWritableWrapper extends AbstractDynamicWrapper {
                 setAttribute(attribute);
                 result.add(attribute);
             } catch (Exception e) {
-                logger.warn("Setting attribute {} failed on {}", attribute.getName(), moduleIdentifier, e);
+                LOGGER.warn("Setting attribute {} failed on {}", attribute.getName(), moduleIdentifier, e);
                 throw new IllegalArgumentException(
                         "Setting attribute failed - " + attribute.getName()
                                 + " on " + moduleIdentifier, e);
index 98f0908dc710cf40fbb93b88004d411d03f594fd..ddb9c52c88337b0b4aaa051828682d88b15eae7b 100644 (file)
@@ -27,7 +27,7 @@ import java.util.List;
 import java.util.Set;
 
 public class InternalJMXRegistrator implements Closeable {
-    private static final Logger logger = LoggerFactory
+    private static final Logger LOGGER = LoggerFactory
             .getLogger(InternalJMXRegistrator.class);
     private final MBeanServer configMBeanServer;
 
@@ -53,6 +53,7 @@ public class InternalJMXRegistrator implements Closeable {
 
     @GuardedBy("this")
     private final Set<ObjectName> registeredObjectNames = new HashSet<>();
+    @GuardedBy("this")
     private final List<InternalJMXRegistrator> children = new ArrayList<>();
 
     public synchronized InternalJMXRegistration registerMBean(Object object,
@@ -79,9 +80,8 @@ public class InternalJMXRegistrator implements Closeable {
         }
     }
 
-    public InternalJMXRegistrator createChild() {
-        InternalJMXRegistrator child = new InternalJMXRegistrator(
-                configMBeanServer);
+    public synchronized InternalJMXRegistrator createChild() {
+        InternalJMXRegistrator child = new InternalJMXRegistrator(configMBeanServer);
         children.add(child);
         return child;
     }
@@ -100,7 +100,7 @@ public class InternalJMXRegistrator implements Closeable {
             try {
                 configMBeanServer.unregisterMBean(on);
             } catch (Exception e) {
-                logger.warn("Ignoring error while unregistering {}", on, e);
+                LOGGER.warn("Ignoring error while unregistering {}", on, e);
             }
         }
         registeredObjectNames.clear();
@@ -137,7 +137,7 @@ public class InternalJMXRegistrator implements Closeable {
         return getSameNames(result);
     }
 
-    private Set<ObjectName> getSameNames(Set<ObjectName> superSet) {
+    private synchronized Set<ObjectName> getSameNames(Set<ObjectName> superSet) {
         Set<ObjectName> result = new HashSet<>(superSet);
         result.retainAll(registeredObjectNames);
         for (InternalJMXRegistrator child : children) {
index 34c0436dafe2dec31fda777eb0f7754ab16dddfa..c0e9b0d101b30bd912ff2674ccc254744356a68f 100644 (file)
@@ -46,9 +46,10 @@ public class ModuleJMXRegistrator implements Closeable {
     public ModuleJMXRegistration registerMBean(Object object, ObjectName on)
             throws InstanceAlreadyExistsException {
         ObjectNameUtil.checkType(on, ObjectNameUtil.TYPE_MODULE);
-        if (ObjectNameUtil.getTransactionName(on) != null)
+        if (ObjectNameUtil.getTransactionName(on) != null) {
             throw new IllegalArgumentException(
                     "Transaction name not expected in " + on);
+        }
         return new ModuleJMXRegistration(childJMXRegistrator.registerMBean(
                 object, on));
     }
index b592fa3c79736d09b22f0b133bef142702783dbb..c03bfa450034254360dca663f18abf54d607f83e 100644 (file)
@@ -49,7 +49,7 @@ public class BeanToOsgiServiceManager {
 
 
     public static class OsgiRegistration implements AutoCloseable {
-        private static final Logger logger = LoggerFactory.getLogger(OsgiRegistration.class);
+        private static final Logger LOGGER = LoggerFactory.getLogger(OsgiRegistration.class);
 
         @GuardedBy("this")
         private AutoCloseable instance;
@@ -89,7 +89,7 @@ public class BeanToOsgiServiceManager {
                 try {
                     serviceRegistration.unregister();
                 } catch(IllegalStateException e) {
-                    logger.trace("Cannot unregister {}", serviceRegistration, e);
+                    LOGGER.trace("Cannot unregister {}", serviceRegistration, e);
                 }
             }
             serviceRegistrations.clear();
@@ -101,7 +101,7 @@ public class BeanToOsgiServiceManager {
             notEquals |= newAnnotationMapping.equals(serviceNamesToAnnotations) == false;
             if (notEquals) {
                 // FIXME: changing from old state to new state can be improved by computing the diff
-                logger.debug("Detected change in service registrations for {}: old: {}, new: {}", moduleIdentifier,
+                LOGGER.debug("Detected change in service registrations for {}: old: {}, new: {}", moduleIdentifier,
                         serviceNamesToAnnotations, newAnnotationMapping);
                 close();
                 this.instance = newInstance;
index 375ef5948712f3bcc5dc803802645b1d6fa56103..b115f1acd94ef837c8b7309be87a86e41e1fd195 100644 (file)
@@ -25,7 +25,7 @@ import org.slf4j.LoggerFactory;
  * functionality.
  */
 public class BlankTransactionServiceTracker implements ServiceTrackerCustomizer<ModuleFactory, Object> {
-    private static final Logger logger = LoggerFactory.getLogger(BlankTransactionServiceTracker.class);
+    private static final Logger LOGGER = LoggerFactory.getLogger(BlankTransactionServiceTracker.class);
 
     public static final int DEFAULT_MAX_ATTEMPTS = 10;
 
@@ -65,7 +65,7 @@ public class BlankTransactionServiceTracker implements ServiceTrackerCustomizer<
             try {
                 // create transaction
                 CommitStatus commitStatus = blankTransaction.hit();
-                logger.debug("Committed blank transaction with status {}", commitStatus);
+                LOGGER.debug("Committed blank transaction with status {}", commitStatus);
                 return;
             } catch (ConflictingVersionException e) {
                 lastException = e;
@@ -76,7 +76,7 @@ public class BlankTransactionServiceTracker implements ServiceTrackerCustomizer<
                     throw new IllegalStateException(interruptedException);
                 }
             } catch (ValidationException e) {
-                logger.error("Validation exception while running blank transaction indicates programming error", e);
+                LOGGER.error("Validation exception while running blank transaction indicates programming error", e);
                 throw new RuntimeException("Validation exception while running blank transaction indicates programming error", e);
             }
         }
index 1e94e5e9c021b1660e02a6d8303333832716ad44..7cb4445328f84355e86ad8590120340354e7df6c 100644 (file)
@@ -25,7 +25,7 @@ import java.util.Map;
  */
 public class BundleContextBackedModuleFactoriesResolver implements
         ModuleFactoriesResolver {
-    private static final Logger logger = LoggerFactory
+    private static final Logger LOGGER = LoggerFactory
             .getLogger(BundleContextBackedModuleFactoriesResolver.class);
     private final BundleContext bundleContext;
 
@@ -62,14 +62,14 @@ public class BundleContextBackedModuleFactoriesResolver implements
             if (serviceReference.getBundle() == null || serviceReference.getBundle().getBundleContext() == null) {
                 throw new NullPointerException("Bundle context of " + factory + " ModuleFactory not found.");
             }
-            logger.debug("Reading factory {} {}", moduleName, factory);
+            LOGGER.debug("Reading factory {} {}", moduleName, factory);
 
             Map.Entry<ModuleFactory, BundleContext> conflicting = result.get(moduleName);
             if (conflicting != null) {
                 String error = String
                         .format("Module name is not unique. Found two conflicting factories with same name '%s': '%s' '%s'",
                                 moduleName, conflicting.getKey(), factory);
-                logger.error(error);
+                LOGGER.error(error);
                 throw new IllegalArgumentException(error);
             } else {
                 result.put(moduleName, new AbstractMap.SimpleImmutableEntry<>(factory,
index 3015ed229e28f1c04015d9d488d641c9ebceb161..3c8fc042a37c5ebe048b8b1e47a1016674b6402c 100644 (file)
@@ -35,7 +35,7 @@ import org.slf4j.LoggerFactory;
  */
 public class ModuleFactoryBundleTracker implements BundleTrackerCustomizer<Object> {
     private final BlankTransactionServiceTracker blankTransactionServiceTracker;
-    private static final Logger logger = LoggerFactory.getLogger(ModuleFactoryBundleTracker.class);
+    private static final Logger LOGGER = LoggerFactory.getLogger(ModuleFactoryBundleTracker.class);
 
     public ModuleFactoryBundleTracker(BlankTransactionServiceTracker blankTransactionServiceTracker) {
         this.blankTransactionServiceTracker = blankTransactionServiceTracker;
@@ -44,7 +44,7 @@ public class ModuleFactoryBundleTracker implements BundleTrackerCustomizer<Objec
     @Override
     public Object addingBundle(Bundle bundle, BundleEvent event) {
         URL resource = bundle.getEntry("META-INF/services/" + ModuleFactory.class.getName());
-        logger.trace("Got addingBundle event of bundle {}, resource {}, event {}",
+        LOGGER.trace("Got addingBundle event of bundle {}, resource {}, event {}",
                 bundle, resource, event);
         if (resource != null) {
             try (InputStream inputStream = resource.openStream()) {
@@ -53,7 +53,7 @@ public class ModuleFactoryBundleTracker implements BundleTrackerCustomizer<Objec
                     registerFactory(factoryClassName, bundle);
                 }
             } catch (Exception e) {
-                logger.error("Error while reading {}", resource, e);
+                LOGGER.error("Error while reading {}", resource, e);
                 throw new RuntimeException(e);
             }
         }
@@ -79,7 +79,7 @@ public class ModuleFactoryBundleTracker implements BundleTrackerCustomizer<Objec
             Class<?> clazz = bundle.loadClass(factoryClassName);
             if (ModuleFactory.class.isAssignableFrom(clazz)) {
                 try {
-                    logger.debug("Registering {} in bundle {}",
+                    LOGGER.debug("Registering {} in bundle {}",
                             clazz.getName(), bundle);
                     return bundle.getBundleContext().registerService(
                             ModuleFactory.class.getName(), clazz.newInstance(),
@@ -111,7 +111,7 @@ public class ModuleFactoryBundleTracker implements BundleTrackerCustomizer<Objec
     }
 
     public static String logMessage(String slfMessage, Object... params) {
-        logger.info(slfMessage, params);
+        LOGGER.info(slfMessage, params);
         String formatMessage = slfMessage.replaceAll("\\{\\}", "%s");
         return format(formatMessage, params);
     }
index 48fdd8855de12c9735a9a10a25ae5b5a9382b7f0..c5be03ca4dc1948fe776ef30b5d171ec0667ce83 100644 (file)
@@ -31,7 +31,7 @@ import org.slf4j.LoggerFactory;
  */
 public final class ModuleInfoBundleTracker implements BundleTrackerCustomizer<Collection<ObjectRegistration<YangModuleInfo>>> {
 
-    private static final Logger logger = LoggerFactory.getLogger(ModuleInfoBundleTracker.class);
+    private static final Logger LOGGER = LoggerFactory.getLogger(ModuleInfoBundleTracker.class);
 
     public static final String MODULE_INFO_PROVIDER_PATH_PREFIX = "META-INF/services/";
 
@@ -45,7 +45,7 @@ public final class ModuleInfoBundleTracker implements BundleTrackerCustomizer<Co
     @Override
     public Collection<ObjectRegistration<YangModuleInfo>> addingBundle(Bundle bundle, BundleEvent event) {
         URL resource = bundle.getEntry(MODULE_INFO_PROVIDER_PATH_PREFIX + YangModelBindingProvider.class.getName());
-        logger.debug("Got addingBundle({}) with YangModelBindingProvider resource {}", bundle, resource);
+        LOGGER.debug("Got addingBundle({}) with YangModelBindingProvider resource {}", bundle, resource);
         if(resource==null) {
             return null;
         }
@@ -54,16 +54,16 @@ public final class ModuleInfoBundleTracker implements BundleTrackerCustomizer<Co
         try (InputStream inputStream = resource.openStream()) {
             List<String> lines = IOUtils.readLines(inputStream);
             for (String moduleInfoName : lines) {
-                logger.trace("Retrieve ModuleInfo({}, {})", moduleInfoName, bundle);
+                LOGGER.trace("Retrieve ModuleInfo({}, {})", moduleInfoName, bundle);
                 YangModuleInfo moduleInfo = retrieveModuleInfo(moduleInfoName, bundle);
                 registrations.add(moduleInfoRegistry.registerModuleInfo(moduleInfo));
             }
 
         } catch (Exception e) {
-            logger.error("Error while reading {}", resource, e);
+            LOGGER.error("Error while reading {}", resource, e);
             throw new RuntimeException(e);
         }
-        logger.trace("Got following registrations {}", registrations);
+        LOGGER.trace("Got following registrations {}", registrations);
         return registrations;
     }
 
@@ -111,7 +111,7 @@ public final class ModuleInfoBundleTracker implements BundleTrackerCustomizer<Co
         } catch (NoClassDefFoundError e) {
 
 
-            logger.error("Error while executing getModuleInfo on {}", instance, e);
+            LOGGER.error("Error while executing getModuleInfo on {}", instance, e);
             throw e;
         }
     }
@@ -126,7 +126,7 @@ public final class ModuleInfoBundleTracker implements BundleTrackerCustomizer<Co
     }
 
     public static String logMessage(String slfMessage, Object... params) {
-        logger.info(slfMessage, params);
+        LOGGER.info(slfMessage, params);
         String formatMessage = slfMessage.replaceAll("\\{\\}", "%s");
         return format(formatMessage, params);
     }
index 510fdf9373f46a7dc0c5f1aa61aabd15d31fbb25..4d94c6d2655650ece2f9bcb1a26a3e0b872a7d60 100644 (file)
@@ -21,6 +21,9 @@ import java.util.Set;
 
 public class InterfacesHelper {
 
+    private InterfacesHelper() {
+    }
+
     public static Set<Class<?>> getAllInterfaces(Class<?> clazz) {
         if (clazz.isInterface()) {
             throw new IllegalArgumentException(clazz
@@ -38,17 +41,17 @@ public class InterfacesHelper {
     }
 
     private static Set<Class<?>> getAllSuperInterfaces(Set<Class<?>> ifcs) {
-        ifcs = new HashSet<>(ifcs); // create copy to modify
+        Set<Class<?>> interfaces = new HashSet<>(ifcs); // create copy to modify
         // each interface can extend other interfaces
         Set<Class<?>> result = new HashSet<>();
-        while (ifcs.size() > 0) {
-            Iterator<Class<?>> iterator = ifcs.iterator();
+        while (!interfaces.isEmpty()) {
+            Iterator<Class<?>> iterator = interfaces.iterator();
             Class<?> ifc = iterator.next();
             iterator.remove();
             if (ifc.isInterface() == false)  {
                 throw new IllegalArgumentException(ifc + " should be an interface");
             }
-            ifcs.addAll(Arrays.asList(ifc.getInterfaces()));
+            interfaces.addAll(Arrays.asList(ifc.getInterfaces()));
             result.add(ifc);
         }
         return result;
index fdde0b23efc53daf2f9b7a33001eb9cad1d4fb6c..284e109f2d11fc0b7d83cd45cf9dfc8cb6605151 100644 (file)
@@ -16,12 +16,15 @@ import org.opendaylight.controller.config.api.LookupRegistry;
 
 public class LookupBeansUtil {
 
+    private LookupBeansUtil() {
+    }
+
     public static ObjectName lookupConfigBean(LookupRegistry lookupRegistry,
             String moduleName, String instanceName)
             throws InstanceNotFoundException {
         Set<ObjectName> objectNames = lookupRegistry.lookupConfigBeans(
                 moduleName, instanceName);
-        if (objectNames.size() == 0) {
+        if (objectNames.isEmpty()) {
             throw new InstanceNotFoundException("No instance found");
         } else if (objectNames.size() > 1) {
             throw new InstanceNotFoundException("Too many instances found");
index f1072a76ae907d934d13984478c119092c9f0dbd..1cb31caea166d62dbc7c343b30b3ad2c440f6f58 100644 (file)
@@ -19,6 +19,9 @@ import java.util.Set;
 
 public class ModuleQNameUtil {
 
+    private ModuleQNameUtil() {
+    }
+
     public static Set<String> getQNames(Map<String, Entry<ModuleFactory, BundleContext>> resolved) {
         Set<String> result = new HashSet<>();
         for (Entry<ModuleFactory, BundleContext> entry : resolved.values()) {
index 2df28f0a154b8b7a6e37f1930b5e06d46efda675..f839452dcadb8e1295e8a1669154ea51699af5f5 100644 (file)
@@ -21,7 +21,10 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class OsgiRegistrationUtil {
-    private static final Logger logger = LoggerFactory.getLogger(OsgiRegistrationUtil.class);
+    private static final Logger LOGGER = LoggerFactory.getLogger(OsgiRegistrationUtil.class);
+
+    private OsgiRegistrationUtil() {
+    }
 
     @SafeVarargs
     public static <T> AutoCloseable registerService(BundleContext bundleContext, T service, Class<? super T> ... interfaces) {
@@ -80,7 +83,7 @@ public class OsgiRegistrationUtil {
                     try {
                         ac.close();
                     } catch (Exception e) {
-                        logger.warn("Exception while closing {}", ac, e);
+                        LOGGER.warn("Exception while closing {}", ac, e);
                         if (firstException == null) {
                             firstException = e;
                         } else {
index 1bf2025c46ee3af3085f77ab6fdf166a54b71846..3e004b4d7cf03a99a7bcfb4e2906f0c437fadf73 100644 (file)
@@ -30,7 +30,7 @@ import com.google.common.base.Preconditions;
  * Delegates the the contained feature and provides additional methods.
  */
 public class AbstractFeatureWrapper implements Feature {
-    private static final Logger logger = LoggerFactory.getLogger(AbstractFeatureWrapper.class);
+    private static final Logger LOGGER = LoggerFactory.getLogger(AbstractFeatureWrapper.class);
     protected Feature feature = null;
 
     protected AbstractFeatureWrapper() {
@@ -55,7 +55,7 @@ public class AbstractFeatureWrapper implements Feature {
             try {
                 snapShotHolders.add(new FeatureConfigSnapshotHolder(c,this));
             } catch (JAXBException e) {
-                logger.debug("{} is not a config subsystem config file",c.getFinalname());
+                LOGGER.debug("{} is not a config subsystem config file",c.getFinalname());
             }
         }
         return snapShotHolders;
@@ -71,18 +71,23 @@ public class AbstractFeatureWrapper implements Feature {
 
     @Override
     public boolean equals(Object obj) {
-        if (this == obj)
+        if (this == obj) {
             return true;
-        if (obj == null)
+        }
+        if (obj == null) {
             return false;
-        if (getClass() != obj.getClass())
+        }
+        if (getClass() != obj.getClass()) {
             return false;
+        }
         AbstractFeatureWrapper other = (AbstractFeatureWrapper) obj;
         if (feature == null) {
-            if (other.feature != null)
+            if (other.feature != null) {
                 return false;
-        } else if (!feature.equals(other.feature))
+            }
+        } else if (!feature.equals(other.feature)) {
             return false;
+        }
         return true;
     }
 
index 8d2ae68a9a3af76c8f0db7c8f50b8739bb25888b..2bff9069007baa515c8f175740a79fe5e1b325a4 100644 (file)
@@ -30,7 +30,7 @@ import com.google.common.base.Preconditions;
  * Delegates the the contained feature and provides additional methods.
  */
 public class ChildAwareFeatureWrapper extends AbstractFeatureWrapper implements Feature {
-    private static final Logger logger = LoggerFactory.getLogger(ChildAwareFeatureWrapper.class);
+    private static final Logger LOGGER = LoggerFactory.getLogger(ChildAwareFeatureWrapper.class);
     private FeaturesService featuresService= null;
 
     protected ChildAwareFeatureWrapper(Feature f) {
@@ -79,7 +79,7 @@ public class ChildAwareFeatureWrapper extends AbstractFeatureWrapper implements
                     f = new FeatureConfigSnapshotHolder(h,this);
                     snapShotHolders.add(f);
                 } catch (JAXBException e) {
-                    logger.debug("{} is not a config subsystem config file",h.getFileInfo().getFinalname());
+                    LOGGER.debug("{} is not a config subsystem config file",h.getFileInfo().getFinalname());
                 }
             }
         }
@@ -95,11 +95,10 @@ public class ChildAwareFeatureWrapper extends AbstractFeatureWrapper implements
         for(Feature f: features) {
             if (f.getName().equals(dependency.getName())) {
                 Version v = VersionTable.getVersion(f.getVersion());
-                if (range.contains(v)) {
-                    if (fi == null || VersionTable.getVersion(fi.getVersion()).compareTo(v) < 0) {
+                if (range.contains(v) &&
+                    (fi == null || VersionTable.getVersion(fi.getVersion()).compareTo(v) < 0)) {
                         fi = f;
                         break;
-                    }
                 }
             }
         }
index b8f18960d109f60d5d33e3683035784387ee0a86..2af471999497dde9d933338e8b66526133e2bbc3 100644 (file)
@@ -19,7 +19,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class ConfigFeaturesListener implements  FeaturesListener,  AutoCloseable {
-    private static final Logger logger = LoggerFactory.getLogger(ConfigFeaturesListener.class);
+    private static final Logger LOGGER = LoggerFactory.getLogger(ConfigFeaturesListener.class);
     private static final int QUEUE_SIZE = 1000;
     private BlockingQueue<FeatureEvent> queue = new LinkedBlockingQueue<FeatureEvent>(QUEUE_SIZE);
     Thread pushingThread = null;
@@ -36,7 +36,7 @@ public class ConfigFeaturesListener implements  FeaturesListener,  AutoCloseable
 
     @Override
     public void repositoryEvent(RepositoryEvent event) {
-        logger.debug("Repository: " + event.getType() + " " + event.getRepository());
+        LOGGER.debug("Repository: " + event.getType() + " " + event.getRepository());
     }
 
     @Override
index d33a8cba92bb552dd8db19f2daebe1c5ccc60c51..abb1dbe9aa060617fc5ac638cb0439a087b2a3a2 100644 (file)
@@ -17,14 +17,14 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class ConfigPusherCustomizer implements ServiceTrackerCustomizer<ConfigPusher, ConfigPusher>, AutoCloseable {
-    private static final Logger logger = LoggerFactory.getLogger(ConfigPusherCustomizer.class);
+    private static final Logger LOGGER = LoggerFactory.getLogger(ConfigPusherCustomizer.class);
     private ConfigFeaturesListener configFeaturesListener = null;
     private FeatureServiceCustomizer featureServiceCustomizer = null;
     private ServiceTracker<FeaturesService,FeaturesService> fsst = null;
 
     @Override
     public ConfigPusher addingService(ServiceReference<ConfigPusher> configPusherServiceReference) {
-        logger.trace("Got ConfigPusherCustomizer.addingService {}", configPusherServiceReference);
+        LOGGER.trace("Got ConfigPusherCustomizer.addingService {}", configPusherServiceReference);
         BundleContext bc = configPusherServiceReference.getBundle().getBundleContext();
         ConfigPusher cpService = bc.getService(configPusherServiceReference);
         featureServiceCustomizer = new FeatureServiceCustomizer(cpService);
index 06c5c920f4ebb4da149e591c14d3c944cd4ccd5b..b0e64b84d2adf4433fd378b8fca5d35eb97c4e19 100644 (file)
@@ -23,7 +23,7 @@ import org.slf4j.LoggerFactory;
 import com.google.common.collect.LinkedHashMultimap;
 
 public class ConfigPushingRunnable implements Runnable {
-    private static final Logger logger = LoggerFactory.getLogger(ConfigPushingRunnable.class);
+    private static final Logger LOGGER = LoggerFactory.getLogger(ConfigPushingRunnable.class);
     private static final int POLL_TIME = 1;
     private BlockingQueue<FeatureEvent> queue;
     private FeatureConfigPusher configPusher;
@@ -49,14 +49,14 @@ public class ConfigPushingRunnable implements Runnable {
                             processFeatureEvent(event,toInstall);
                         }
                 } else if(toInstall.isEmpty()) {
-                    logger.error("ConfigPushingRunnable - exiting");
+                    LOGGER.error("ConfigPushingRunnable - exiting");
                     return;
                 }
             } catch (InterruptedException e) {
-                logger.error("ConfigPushingRunnable - interupted");
+                LOGGER.error("ConfigPushingRunnable - interupted");
                 interuppted = true;
             } catch (Exception e) {
-                logger.error("Exception while processing features {}", e);
+                LOGGER.error("Exception while processing features {}", e);
             }
         }
     }
@@ -73,7 +73,7 @@ public class ConfigPushingRunnable implements Runnable {
 
     protected void logPushResult(LinkedHashMultimap<Feature,FeatureConfigSnapshotHolder> results) {
         for(Feature f:results.keySet()) {
-            logger.info("Pushed configs for feature {} {}",f,results.get(f));
+            LOGGER.info("Pushed configs for feature {} {}",f,results.get(f));
         }
     }
 }
index 17099f9d3355d948c877538bc76b0f1f8f21285e..5c5061277b62f28c98e163f17c7fc1c721a91cd9 100644 (file)
@@ -25,7 +25,7 @@ import com.google.common.collect.LinkedHashMultimap;
  * Simple class to push configs to the config subsystem from Feature's configfiles
  */
 public class FeatureConfigPusher {
-    private static final Logger logger = LoggerFactory.getLogger(FeatureConfigPusher.class);
+    private static final Logger LOGGER = LoggerFactory.getLogger(FeatureConfigPusher.class);
     private static final int MAX_RETRIES=100;
     private static final int RETRY_PAUSE_MILLIS=1;
     private FeaturesService featuresService = null;
@@ -90,13 +90,13 @@ public class FeatureConfigPusher {
                 if(installedFeatures.contains(feature)) {
                     return true;
                 } else {
-                    logger.warn("Karaf featuresService.listInstalledFeatures() has not yet finished installing feature (retry {}) {} {}",retries,feature.getName(),feature.getVersion());
+                    LOGGER.warn("Karaf featuresService.listInstalledFeatures() has not yet finished installing feature (retry {}) {} {}",retries,feature.getName(),feature.getVersion());
                 }
             } catch (Exception e) {
                 if(retries < MAX_RETRIES) {
-                    logger.warn("Karaf featuresService.listInstalledFeatures() has thrown an exception, retry {}, Exception {}", retries,e);
+                    LOGGER.warn("Karaf featuresService.listInstalledFeatures() has thrown an exception, retry {}, Exception {}", retries,e);
                 } else {
-                    logger.error("Giving up on Karaf featuresService.listInstalledFeatures() which has thrown an exception, retry {}, Exception {}", retries,e);
+                    LOGGER.error("Giving up on Karaf featuresService.listInstalledFeatures() which has thrown an exception, retry {}, Exception {}", retries,e);
                     throw e;
                 }
             }
@@ -106,7 +106,7 @@ public class FeatureConfigPusher {
                 throw new IllegalStateException(e1);
             }
         }
-        logger.error("Giving up (after {} retries) on Karaf featuresService.listInstalledFeatures() which has not yet finished installing feature {} {}",MAX_RETRIES,feature.getName(),feature.getVersion());
+        LOGGER.error("Giving up (after {} retries) on Karaf featuresService.listInstalledFeatures() which has not yet finished installing feature {} {}",MAX_RETRIES,feature.getName(),feature.getVersion());
         return false;
     }
 
index e75c62b81db8dce90184d7142042a00fbce3a88f..02f9f8b80a4e0d4483249359c4272223affa23fd 100644 (file)
@@ -31,7 +31,7 @@ import java.util.SortedSet;
  * StorageAdapter that stores configuration in an xml file.
  */
 public class XmlFileStorageAdapter implements StorageAdapter, Persister {
-    private static final Logger logger = LoggerFactory.getLogger(XmlFileStorageAdapter.class);
+    private static final Logger LOGGER = LoggerFactory.getLogger(XmlFileStorageAdapter.class);
 
     public static final String FILE_STORAGE_PROP = "fileStorage";
     public static final String NUMBER_OF_BACKUPS = "numberOfBackups";
@@ -42,15 +42,15 @@ public class XmlFileStorageAdapter implements StorageAdapter, Persister {
     @Override
     public Persister instantiate(PropertiesProvider propertiesProvider) {
         File storage = extractStorageFileFromProperties(propertiesProvider);
-        logger.debug("Using file {}", storage.getAbsolutePath());
+        LOGGER.debug("Using file {}", storage.getAbsolutePath());
         // Create file if it does not exist
         File parentFile = storage.getAbsoluteFile().getParentFile();
         if (parentFile.exists() == false) {
-            logger.debug("Creating parent folders {}", parentFile);
+            LOGGER.debug("Creating parent folders {}", parentFile);
             parentFile.mkdirs();
         }
         if (storage.exists() == false) {
-            logger.debug("Storage file does not exist, creating empty file");
+            LOGGER.debug("Storage file does not exist, creating empty file");
             try {
                 boolean result = storage.createNewFile();
                 if (result == false)
@@ -87,7 +87,7 @@ public class XmlFileStorageAdapter implements StorageAdapter, Persister {
         } else {
             numberOfStoredBackups = Integer.MAX_VALUE;
         }
-        logger.trace("Property {} set to {}", NUMBER_OF_BACKUPS, numberOfStoredBackups);
+        LOGGER.trace("Property {} set to {}", NUMBER_OF_BACKUPS, numberOfStoredBackups);
         return result;
     }
 
@@ -110,10 +110,11 @@ public class XmlFileStorageAdapter implements StorageAdapter, Persister {
 
         Optional<ConfigSnapshot> lastSnapshot = Config.fromXml(storage).getLastSnapshot();
 
-        if (lastSnapshot.isPresent())
+        if (lastSnapshot.isPresent()) {
             return Lists.newArrayList(toConfigSnapshot(lastSnapshot.get()));
-        else
+        } else {
             return Collections.emptyList();
+        }
     }
 
 
index 7c069dab6b0fb04bbd511fefffbfc5ebf3be6879..03b03befe06f3074ad32cc98ceebb89b78e54f94 100644 (file)
@@ -59,7 +59,7 @@ public class ConfigSnapshot {
 
     @Override
     public String toString() {
-        final StringBuffer sb = new StringBuffer("ConfigSnapshot{");
+        final StringBuilder sb = new StringBuilder("ConfigSnapshot{");
         sb.append("configSnapshot='").append(configSnapshot).append('\'');
         sb.append(", capabilities=").append(capabilities);
         sb.append('}');
index 3c544d4e499b28c5da124658da617d4d249af987..3c5f0bdab6b0de6029e0e93084a254b44867eba1 100644 (file)
@@ -12,15 +12,17 @@ import javax.xml.bind.annotation.adapters.XmlAdapter;
 final class StringTrimAdapter extends XmlAdapter<String, String> {
     @Override
     public String unmarshal(String v) throws Exception {
-        if (v == null)
+        if (v == null) {
             return null;
+        }
         return v.trim();
     }
 
     @Override
     public String marshal(String v) throws Exception {
-        if (v == null)
+        if (v == null) {
             return null;
+        }
         return v.trim();
     }
 }
index 559993f2648ec013791bdcf7167e412fe9a69102..11f64e959b450eec42b744c8cfdabd3d91d66594 100644 (file)
@@ -74,16 +74,17 @@ public class ConfigRegistryJMXClient implements ConfigRegistryClient {
      */
     @Deprecated
     public <T> T newMBeanProxy(ObjectName on, Class<T> clazz) {
-        on = translateServiceRefIfPossible(on, clazz, configMBeanServer);
-        return JMX.newMBeanProxy(configMBeanServer, on, clazz);
+        ObjectName onObj = translateServiceRefIfPossible(on, clazz, configMBeanServer);
+        return JMX.newMBeanProxy(configMBeanServer, onObj, clazz);
     }
 
     static  ObjectName translateServiceRefIfPossible(ObjectName on, Class<?> clazz, MBeanServer configMBeanServer) {
-        if (ObjectNameUtil.isServiceReference(on) && clazz.equals(ServiceReferenceMXBean.class) == false) {
-            ServiceReferenceMXBean proxy = JMX.newMXBeanProxy(configMBeanServer, on, ServiceReferenceMXBean.class);
-            on = proxy.getCurrentImplementation();
+        ObjectName onObj = on;
+        if (ObjectNameUtil.isServiceReference(onObj) && clazz.equals(ServiceReferenceMXBean.class) == false) {
+            ServiceReferenceMXBean proxy = JMX.newMXBeanProxy(configMBeanServer, onObj, ServiceReferenceMXBean.class);
+            onObj = proxy.getCurrentImplementation();
         }
-        return on;
+        return onObj;
     }
 
 
index bc188515538485f9a13f87366a281a893a5984ae..20e26f6508513a70c60694586e8351e9e84709bc 100644 (file)
@@ -45,12 +45,13 @@ public class ConfigTransactionJMXClient implements ConfigTransactionClient {
     }
 
     public <T> T newMXBeanProxy(ObjectName on, Class<T> clazz) {
+        ObjectName onName = on;
         // if on is without transaction, add it. Reason is that when using getters on MXBeans the transaction name is stripped
-        on = ObjectNameUtil.withTransactionName(on, getTransactionName());
+        onName = ObjectNameUtil.withTransactionName(onName, getTransactionName());
         // if this is service reference and user requests for implementation, look it up
-        on = ConfigRegistryJMXClient.translateServiceRefIfPossible(on, clazz, configMBeanServer);
-        on = ObjectNameUtil.withTransactionName(on, getTransactionName());
-        return JMX.newMXBeanProxy(configMBeanServer, on, clazz);
+        onName = ConfigRegistryJMXClient.translateServiceRefIfPossible(onName, clazz, configMBeanServer);
+        onName = ObjectNameUtil.withTransactionName(onName, getTransactionName());
+        return JMX.newMXBeanProxy(configMBeanServer, onName, clazz);
     }
 
     /**
@@ -260,9 +261,10 @@ public class ConfigTransactionJMXClient implements ConfigTransactionClient {
 
     @Override
     public void setAttribute(ObjectName on, String attrName, Attribute attribute) {
-        if (ObjectNameUtil.getTransactionName(on) == null)
+        if (ObjectNameUtil.getTransactionName(on) == null) {
             throw new IllegalArgumentException("Not in transaction instance "
                     + on + ", no transaction name present");
+        }
 
         try {
             configMBeanServer.setAttribute(on, attribute);
@@ -274,9 +276,10 @@ public class ConfigTransactionJMXClient implements ConfigTransactionClient {
 
     @Override
     public Attribute getAttribute(ObjectName on, String attrName) {
-        if (ObjectNameUtil.getTransactionName(on) == null)
+        if (ObjectNameUtil.getTransactionName(on) == null) {
             throw new IllegalArgumentException("Not in transaction instance "
                     + on + ", no transaction name present");
+        }
 
         try {
             return new Attribute(attrName, configMBeanServer.getAttribute(on,attrName));
index 9837a04e7f903daf5c16b906d36e46f2f72cc6e7..ff7da5df483556a9eb2a7bdb2e4e89a03bbff0df 100644 (file)
@@ -38,7 +38,7 @@ import com.google.common.collect.Sets;
 public class ContextSetterImpl implements ContextSetter, Closeable {
 
     private final LogbackStatusListener statusListener;
-    private static final org.slf4j.Logger classLogger = LoggerFactory.getLogger(ContextSetterImpl.class);
+    private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(ContextSetterImpl.class);
 
     public ContextSetterImpl(LogbackRuntimeRegistrator rootRuntimeBeanRegistratorWrapper) {
         statusListener = new LogbackStatusListener(rootRuntimeBeanRegistratorWrapper);
@@ -83,11 +83,11 @@ public class ContextSetterImpl implements ContextSetter, Closeable {
         Map<String, Appender<ILoggingEvent>> appendersMap = getAppenders(module, context);
 
         for (LoggerTO logger : module.getLoggerTO()) {
-            classLogger.trace("Setting configuration for logger {}", logger.getLoggerName());
+            LOGGER.trace("Setting configuration for logger {}", logger.getLoggerName());
             final ch.qos.logback.classic.Logger logbackLogger = context.getLogger(logger.getLoggerName());
 
             Optional<Set<Appender<ILoggingEvent>>> appendersBefore = getAppendersBefore(loggersBefore, logbackLogger);
-            classLogger.trace("Logger {}: Appenders registered before: {}", logger.getLoggerName(),
+            LOGGER.trace("Logger {}: Appenders registered before: {}", logger.getLoggerName(),
                     appendersBefore.isPresent() ? appendersBefore.get() : "NO APPENDERS BEFORE");
 
             logbackLogger.setLevel(Level.toLevel(logger.getLevel()));
@@ -103,7 +103,7 @@ public class ContextSetterImpl implements ContextSetter, Closeable {
             for (String appenderName : logger.getAppenders()) {
                 if (appendersMap.containsKey(appenderName)) {
                     logbackLogger.addAppender(appendersMap.get(appenderName));
-                    classLogger.trace("Logger {}: Adding new appender: {}", logger.getLoggerName(), appenderName);
+                    LOGGER.trace("Logger {}: Adding new appender: {}", logger.getLoggerName(), appenderName);
                 } else {
                     throw new IllegalStateException("No appender " + appenderName
                             + " found. This error should have been discovered by validation");
@@ -118,7 +118,7 @@ public class ContextSetterImpl implements ContextSetter, Closeable {
             for (Appender<ILoggingEvent> appenderBefore : appendersBefore.get()) {
                 logbackLogger.detachAppender(appenderBefore);
                 appenderBefore.stop();
-                classLogger.trace("Logger {}: Removing old appender: {}", logger.getLoggerName(),
+                LOGGER.trace("Logger {}: Removing old appender: {}", logger.getLoggerName(),
                         appenderBefore.getName());
             }
             loggersBefore.remove(logbackLogger);
@@ -134,8 +134,9 @@ public class ContextSetterImpl implements ContextSetter, Closeable {
                 appendersBefore.add(appenderIt.next());
             }
             return Optional.of(appendersBefore);
-        } else
+        } else {
             return Optional.absent();
+        }
 
     }
 
index 5a91796ed602d4f239dae51e9ffd14cbd9038f48..b5d0d1b4de0466e1d1c09d55e92644abf6bb4dd7 100644 (file)
@@ -173,10 +173,11 @@ public class LogbackModuleFactory extends
                 context.getLogger(Logger.ROOT_LOGGER_NAME));
         for (org.slf4j.Logger log : loggersToBeAdd) {
             LoggerTO logger = new LoggerTO();
-            if (((Logger) log).getLevel() != null)
+            if (((Logger) log).getLevel() != null) {
                 logger.setLevel(((Logger) log).getLevel().levelStr);
-            else
+            } else {
                 logger.setLevel(((Logger) log).getEffectiveLevel().levelStr);
+            }
             logger.setLoggerName(log.getName());
             Iterator<Appender<ILoggingEvent>> iter = ((Logger) log).iteratorForAppenders();
             while (iter.hasNext()) {
index 4cc9cc3dde0e91b7c35f98f28206ae69845c04c2..54c87604a433298824fc33ae12a6dc11732dfa92 100644 (file)
@@ -21,12 +21,12 @@ import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
 
 public class ImmediateEventExecutorModuleTest extends AbstractConfigTest {
 
-    private GlobalEventExecutorModuleFactory factory;
+    private ImmediateEventExecutorModuleFactory factory;
     private final String instanceName = ImmediateEventExecutorModuleFactory.SINGLETON_NAME;
 
     @Before
     public void setUp() {
-        factory = new GlobalEventExecutorModuleFactory();
+        factory = new ImmediateEventExecutorModuleFactory();
         super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext,factory));
     }
 
index dd2b504da9a03ab6807efc22adef2c1cf16c990b..cd0f491ebc949c610e925916fc41628eb1a03607 100644 (file)
@@ -41,18 +41,18 @@ import java.util.Map.Entry;
 
 final class CodeWriter {
 
-    private static final Logger logger = LoggerFactory.getLogger(CodeWriter.class);
-    private static final Optional<String> copyright = StringUtil.loadCopyright();
+    private static final Logger LOGGER = LoggerFactory.getLogger(CodeWriter.class);
+    private static final Optional<String> COPYRIGHT = StringUtil.loadCopyright();
 
     public File writeSie(ServiceInterfaceEntry sie, File outputBaseDir) {
         try {
             GeneralInterfaceTemplate generalInterfaceTemplate = TemplateFactory.serviceInterfaceFromSie(sie);
-            GeneratedObject go = new GenericGeneratedObjectFactory().toGeneratedObject(generalInterfaceTemplate, copyright);
+            GeneratedObject go = new GenericGeneratedObjectFactory().toGeneratedObject(generalInterfaceTemplate, COPYRIGHT);
             return go.persist(outputBaseDir).get().getValue();
         } catch (Exception e) {
             String message = "An error occurred during Service interface generating, sie:"
                     + sie.getTypeName() + ", " + sie.getFullyQualifiedName();
-            logger.error(message, e);
+            LOGGER.error(message, e);
             throw new RuntimeException(message, e);
         }
     }
@@ -70,33 +70,33 @@ final class CodeWriter {
             // TOs
             Map<String,GeneralClassTemplate> tosFromMbe = TemplateFactory.tOsFromMbe(mbe);
             for(GeneralClassTemplate template: tosFromMbe.values()) {
-                gos.put(new GenericGeneratedObjectFactory().toGeneratedObject(template, copyright), true);
+                gos.put(new GenericGeneratedObjectFactory().toGeneratedObject(template, COPYRIGHT), true);
             }
 
             // MXBean interface
             GeneralInterfaceTemplate ifcTemplate = TemplateFactory.mXBeanInterfaceTemplateFromMbe(mbe);
-            gos.put(new GenericGeneratedObjectFactory().toGeneratedObject(ifcTemplate, copyright), true);
+            gos.put(new GenericGeneratedObjectFactory().toGeneratedObject(ifcTemplate, COPYRIGHT), true);
 
 
             // generate abstract factory
-            gos.put(new AbsFactoryGeneratedObjectFactory().toGeneratedObject(mbe, copyright), true);
+            gos.put(new AbsFactoryGeneratedObjectFactory().toGeneratedObject(mbe, COPYRIGHT), true);
 
             // generate abstract module
-            gos.put(new AbsModuleGeneratedObjectFactory().toGeneratedObject(mbe, copyright), true);
+            gos.put(new AbsModuleGeneratedObjectFactory().toGeneratedObject(mbe, COPYRIGHT), true);
 
             // generate concrete factory
             StubFactoryTemplate concreteFactory = TemplateFactory.stubFactoryTemplateFromMbe(mbe);
-            gos.put(new GenericGeneratedObjectFactory().toGeneratedObject(concreteFactory, copyright), false);
+            gos.put(new GenericGeneratedObjectFactory().toGeneratedObject(concreteFactory, COPYRIGHT), false);
 
 
             // generate concrete module
 
-            gos.put(new ConcreteModuleGeneratedObjectFactory().toGeneratedObject(mbe, copyright, Optional.<String>absent()), false);
+            gos.put(new ConcreteModuleGeneratedObjectFactory().toGeneratedObject(mbe, COPYRIGHT, Optional.<String>absent()), false);
 
             // write runtime bean MXBeans and registrators
             List<FtlTemplate> allFtlFiles = getRuntimeBeanFtlTemplates(mbe.getRuntimeBeans());
             for(FtlTemplate template: allFtlFiles) {
-                gos.put(new GenericGeneratedObjectFactory().toGeneratedObject(template, copyright), true);
+                gos.put(new GenericGeneratedObjectFactory().toGeneratedObject(template, COPYRIGHT), true);
             }
 
             generatedFiles.addAll(persistGeneratedObjects(targetBaseDir, mainBaseDir, gos));
@@ -113,7 +113,7 @@ final class CodeWriter {
         } catch (Exception e) {
             String message = "An error occurred during Module generating, mbe:"
                     + mbe.getJavaNamePrefix();
-            logger.error(message, e);
+            LOGGER.error(message, e);
             throw new RuntimeException(message, e);
         }
     }
index 1b8905b9871c0a1334ebacbc28a1f6dd52d41492..c8356274f8144095581e504e8b45680051be319d 100644 (file)
@@ -54,7 +54,7 @@ public class JMXGenerator implements CodeGenerator {
 
     private PackageTranslator packageTranslator;
     private final CodeWriter codeWriter;
-    private static final Logger logger = LoggerFactory
+    private static final Logger LOGGER = LoggerFactory
             .getLogger(JMXGenerator.class);
     private Map<String, String> namespaceToPackageMapping;
     private File resourceBaseDir;
@@ -83,8 +83,9 @@ public class JMXGenerator implements CodeGenerator {
 
         packageTranslator = new PackageTranslator(namespaceToPackageMapping);
 
-        if (!outputBaseDir.exists())
+        if (!outputBaseDir.exists()) {
             outputBaseDir.mkdirs();
+        }
 
         GeneratedFilesTracker generatedFiles = new GeneratedFilesTracker();
         // create SIE structure qNamesToSIEs
@@ -127,7 +128,7 @@ public class JMXGenerator implements CodeGenerator {
         Preconditions.checkNotNull(resourceBaseDir,
                 "resource base dir attribute was null");
 
-        StringBuffer fullyQualifiedNamesOfFactories = new StringBuffer();
+        StringBuilder fullyQualifiedNamesOfFactories = new StringBuilder();
         // create MBEs
         for (Module module : yangModulesInCurrentMavenModule) {
             String packageName = packageTranslator.getPackageName(module);
@@ -166,7 +167,7 @@ public class JMXGenerator implements CodeGenerator {
                         fullyQualifiedNamesOfFactories.toString());
             } catch (IOException e) {
                 String message = "Cannot write to " + serviceLoaderFile;
-                logger.error(message);
+                LOGGER.error(message);
                 throw new RuntimeException(message, e);
             }
         }
@@ -184,10 +185,11 @@ public class JMXGenerator implements CodeGenerator {
 
     @Override
     public void setAdditionalConfig(Map<String, String> additionalCfg) {
-        if (logger != null)
-            logger.debug(getClass().getCanonicalName(),
+        if (LOGGER != null) {
+            LOGGER.debug(getClass().getCanonicalName(),
                     ": Additional configuration received: ",
                     additionalCfg.toString());
+        }
         this.namespaceToPackageMapping = extractNamespaceMapping(additionalCfg);
         this.generateModuleFactoryFile = extractModuleFactoryBoolean(additionalCfg);
     }
@@ -195,10 +197,12 @@ public class JMXGenerator implements CodeGenerator {
     private boolean extractModuleFactoryBoolean(
             Map<String, String> additionalCfg) {
         String bool = additionalCfg.get(MODULE_FACTORY_FILE_BOOLEAN);
-        if (bool == null)
+        if (bool == null) {
             return true;
-        if (bool.equals("false"))
+        }
+        if ("false".equals(bool)) {
             return false;
+        }
         return true;
     }
 
@@ -250,8 +254,8 @@ public class JMXGenerator implements CodeGenerator {
     public void setMavenProject(MavenProject project) {
         this.projectBaseDir = project.getBasedir();
 
-        if (logger != null)
-            logger.debug(getClass().getCanonicalName(), " project base dir: ",
+        if (LOGGER != null)
+            LOGGER.debug(getClass().getCanonicalName(), " project base dir: ",
                     projectBaseDir);
     }
 
@@ -268,7 +272,7 @@ public class JMXGenerator implements CodeGenerator {
                     }
                 }
                 if (undeletedFiles.isEmpty() == false) {
-                    logger.error(
+                    LOGGER.error(
                             "Illegal state occurred: Unable to delete already generated files, undeleted files: {}",
                             undeletedFiles);
                 }
index c3e51d6550e50344ed8fc1c9ad5c46f6282af7cc..c3a00b93da1b4d88a763ba07ee726a8b8966d382 100644 (file)
@@ -19,14 +19,14 @@ import java.util.List;
 
 public class AbstractFactoryTemplate extends GeneralClassTemplate {
 
-    private static final List<String> implementedIfcs = Lists
+    private static final List<String> IMPLEMENTED_IFCS = Lists
             .newArrayList(ModuleFactory.class.getCanonicalName());
 
     public AbstractFactoryTemplate(Header header, String packageName,
                                    String abstractFactoryName,
                                    List<Field> fields) {
         super(header, packageName, abstractFactoryName, Collections
-                .<String> emptyList(), implementedIfcs, fields, Collections
+                .<String> emptyList(), IMPLEMENTED_IFCS, fields, Collections
                 .<MethodDefinition> emptyList(), true, false, Collections
                 .<Constructor> emptyList());
     }
index d07edae14ee42283827ddf8c52cb6ce9d92aba44..aa696450a94e8a5971fd96c58bcbb6e17edfaab9 100644 (file)
@@ -108,7 +108,7 @@ public class RuntimeRegistratorFtlTemplate extends GeneralClassTemplate {
                     .getFullyQualifiedName(rootRB.getPackageName(), rootRB.getJavaNameOfRuntimeMXBean());
             String childRegistratorFQN = rootFtlFile.getFullyQualifiedName();
             Field rbParameter = new Field(fullyQualifiedNameOfMXBean, "rb");
-            StringBuffer registerBody = new StringBuffer();
+            StringBuilder registerBody = new StringBuilder();
             registerBody.append(format("%s %s = this.%s.registerRoot(%s);\n",
                     HierarchicalRuntimeBeanRegistration.class
                             .getCanonicalName(), hierachchicalRegistration
@@ -200,12 +200,12 @@ public class RuntimeRegistratorFtlTemplate extends GeneralClassTemplate {
                 unorderedResult.put(entry.getKey(), entry.getValue());
             }
 
-            if (childRegistratorMap.size() > 0) {
+            if (!childRegistratorMap.isEmpty()) {
                 // first entry is the direct descendant according to the create
                 // contract
                 RuntimeRegistratorFtlTemplate childRegistrator = childRegistratorMap
                         .values().iterator().next();
-                StringBuffer body = new StringBuffer();
+                StringBuilder body = new StringBuilder();
                 String key, value;
                 key = child.getJavaNamePrefix();
                 body.append(format(
index 7b7aab85597eafbd4fcb113abfea20dfe19c49d1..f8f5cd6742a1182e47c7194fb3ec215316ce7ca5 100644 (file)
@@ -113,7 +113,7 @@ public class TemplateFactory {
     static String serializeType(Type type, boolean addWildcards) {
         if (type instanceof ParameterizedType){
             ParameterizedType parameterizedType = (ParameterizedType) type;
-            StringBuffer sb = new StringBuffer();
+            StringBuilder sb = new StringBuilder();
             sb.append(parameterizedType.getRawType().getFullyQualifiedName());
             sb.append(addWildcards ? "<? extends " : "<");
             boolean first = true;
@@ -282,12 +282,15 @@ public class TemplateFactory {
         for (Rpc rpc : rbe.getRpcs()) {
             AttributeIfc returnType = rpc.getReturnType();
 
-            if (returnType == VoidAttribute.getInstance())
+            if (returnType == VoidAttribute.getInstance()) {
                 continue;
-            if (returnType instanceof JavaAttribute)
+            }
+            if (returnType instanceof JavaAttribute) {
                 continue;
-            if (returnType instanceof ListAttribute && returnType.getOpenType() instanceof SimpleType)
+            }
+            if (returnType instanceof ListAttribute && returnType.getOpenType() instanceof SimpleType) {
                 continue;
+            }
 
             Preconditions.checkState(yangPropertiesToTypesMap.containsKey(returnType.getAttributeYangName()) == false,
                     "Duplicate TO %s for %s", returnType.getAttributeYangName(), rbe);
@@ -449,7 +452,6 @@ public class TemplateFactory {
                 String returnType;
                 AttributeIfc attributeIfc = attrEntry.getValue();
 
-                boolean isIdentityRef = false;
                 if (attributeIfc instanceof TypedAttribute) {
                     TypedAttribute typedAttribute = (TypedAttribute) attributeIfc;
                     returnType = serializeType(typedAttribute.getType());
index 775fa9fc20d97b10a48859703a4572f03b65d2ca..8cc0ffa165a8d63f387dcb1dd9812b0ec0764124 100644 (file)
@@ -11,6 +11,9 @@ import org.opendaylight.yangtools.yang.common.QName;
 
 public class ConfigConstants {
 
+    private ConfigConstants() {
+    }
+
     public static final String CONFIG_NAMESPACE = "urn:opendaylight:params:xml:ns:yang:controller:config";
 
     public static final String CONFIG_MODULE = "config";
index e9f0ac817675d90a9c9257456d0f9c03c7106719..f99d378b6f3e9175be67fed5284827d0ff50b4db 100644 (file)
@@ -93,22 +93,22 @@ final class ModuleMXBeanEntryBuilder {
         return this;
     }
 
-    private static final Logger logger = LoggerFactory
+    private static final Logger LOGGER = LoggerFactory
             .getLogger(ModuleMXBeanEntryBuilder.class);
 
     // TODO: the XPath should be parsed by code generator IMO
     private static final String MAGIC_STRING = "MAGIC_STRING";
     private static final String MODULE_CONDITION_XPATH_TEMPLATE = "^/MAGIC_STRING:modules/MAGIC_STRING:module/MAGIC_STRING:type\\s*=\\s*['\"](.+)['\"]$";
-    private static final SchemaPath expectedConfigurationAugmentationSchemaPath = SchemaPath.create(true,
+    private static final SchemaPath EXPECTED_CONFIGURATION_AUGMENTATION_SCHEMA_PATH = SchemaPath.create(true,
             createConfigQName("modules"), createConfigQName("module"), createConfigQName("configuration"));
-    private static final SchemaPath expectedStateAugmentationSchemaPath = SchemaPath.create(true,
+    private static final SchemaPath EXPECTED_STATE_AUGMENTATION_SCHEMA_PATH = SchemaPath.create(true,
             createConfigQName("modules"), createConfigQName("module"), createConfigQName("state"));
     private static final Pattern PREFIX_COLON_LOCAL_NAME = Pattern
             .compile("^(.+):(.+)$");
 
 
     public Map<String, ModuleMXBeanEntry> build() {
-        logger.debug("Generating ModuleMXBeans of {} to package {}",
+        LOGGER.debug("Generating ModuleMXBeans of {} to package {}",
                 currentModule.getNamespace(), packageName);
 
         String configModulePrefix;
@@ -146,7 +146,7 @@ final class ModuleMXBeanEntryBuilder {
         checkAttributeNamesUniqueness(uniqueGeneratedClassesNames, result);
         checkUnaugumentedIdentities(unaugmentedModuleIdentities);
 
-        logger.debug("Number of ModuleMXBeans to be generated: {}", result.size());
+        LOGGER.debug("Number of ModuleMXBeans to be generated: {}", result.size());
 
         return result;
     }
@@ -166,7 +166,7 @@ final class ModuleMXBeanEntryBuilder {
 
     private static void checkUnaugumentedIdentities(final Map<String, IdentitySchemaNode> unaugmentedModuleIdentities) {
         if (unaugmentedModuleIdentities.size() > 0) {
-            logger.warn("Augmentation not found for all currentModule identities: {}",
+            LOGGER.warn("Augmentation not found for all currentModule identities: {}",
                     unaugmentedModuleIdentities.keySet());
         }
     }
@@ -190,7 +190,7 @@ final class ModuleMXBeanEntryBuilder {
                             + identityLocalName);
                 } else {
                     moduleIdentities.put(identityLocalName, id);
-                    logger.debug("Found identity {}", identityLocalName);
+                    LOGGER.debug("Found identity {}", identityLocalName);
                 }
                 // validation check on unknown schema nodes
                 boolean providedServiceWasSet = false;
@@ -270,13 +270,13 @@ final class ModuleMXBeanEntryBuilder {
 
         HAS_CHILDREN_AND_QNAME dataNodeContainer = getDataNodeContainer(choiceCaseNode);
 
-        if (expectedConfigurationAugmentationSchemaPath.equals(augmentation.getTargetPath())) {
-            logger.debug("Parsing configuration of {}", moduleLocalNameFromXPath);
+        if (EXPECTED_CONFIGURATION_AUGMENTATION_SCHEMA_PATH.equals(augmentation.getTargetPath())) {
+            LOGGER.debug("Parsing configuration of {}", moduleLocalNameFromXPath);
             yangToAttributes = fillConfiguration(dataNodeContainer, currentModule, typeProviderWrapper, qNamesToSIEs,
                     schemaContext, packageName);
             checkUniqueAttributesWithGeneratedClass(uniqueGeneratedClassesNames, when.getQName(), yangToAttributes);
-        } else if (expectedStateAugmentationSchemaPath.equals(augmentation.getTargetPath())) {
-            logger.debug("Parsing state of {}", moduleLocalNameFromXPath);
+        } else if (EXPECTED_STATE_AUGMENTATION_SCHEMA_PATH.equals(augmentation.getTargetPath())) {
+            LOGGER.debug("Parsing state of {}", moduleLocalNameFromXPath);
             try {
                 runtimeBeans = fillRuntimeBeans(dataNodeContainer, currentModule, typeProviderWrapper, packageName,
                         moduleLocalNameFromXPath, javaNamePrefix);
index ccd701d1fb36a2bba58093999a21aa23c7ac5c08..10267b28e7b6a729b8125c6564a5bf14636da318 100644 (file)
@@ -12,6 +12,9 @@ import org.opendaylight.yangtools.yang.model.api.Module;
 
 public class ModuleUtil {
 
+    private ModuleUtil() {
+    }
+
     public static QName getQName(final Module currentModule) {
         return QName.create(currentModule.getNamespace(), currentModule.getRevision(), currentModule.getName());
     }
index a6a1ac7dc391b05267e71e1575d5f4d7d6cd5396..a7f6f2f221e295ebbf4b17b0ea7c869f1265ace8 100644 (file)
@@ -58,19 +58,20 @@ public class PackageTranslator {
 
     // TODO add to PackageTranslator
     private static String sanitizePackage(String namespace) {
-        namespace = namespace.replace("://", ".");
-        namespace = namespace.replace("/", ".");
-        namespace = namespace.replace(":", ".");
-        namespace = namespace.replace("-", "_");
-        namespace = namespace.replace("@", ".");
-        namespace = namespace.replace("$", ".");
-        namespace = namespace.replace("#", ".");
-        namespace = namespace.replace("'", ".");
-        namespace = namespace.replace("*", ".");
-        namespace = namespace.replace("+", ".");
-        namespace = namespace.replace(",", ".");
-        namespace = namespace.replace(";", ".");
-        namespace = namespace.replace("=", ".");
-        return namespace;
+        String newNamespace = namespace;
+        newNamespace = newNamespace.replace("://", ".");
+        newNamespace = newNamespace.replace("/", ".");
+        newNamespace = newNamespace.replace(":", ".");
+        newNamespace = newNamespace.replace("-", "_");
+        newNamespace = newNamespace.replace("@", ".");
+        newNamespace = newNamespace.replace("$", ".");
+        newNamespace = newNamespace.replace("#", ".");
+        newNamespace = newNamespace.replace("'", ".");
+        newNamespace = newNamespace.replace("*", ".");
+        newNamespace = newNamespace.replace("+", ".");
+        newNamespace = newNamespace.replace(",", ".");
+        newNamespace = newNamespace.replace(";", ".");
+        newNamespace = newNamespace.replace("=", ".");
+        return newNamespace;
     }
 }
index 67f624175b00aacff88369aa8fce5fe00ce5a961..aec41152de5fda3138430091e41344bc059feeaf 100644 (file)
@@ -217,8 +217,6 @@ public class RuntimeBeanEntry {
             final Map<QName, Set<RpcDefinition>> identitiesToRpcs) {
 
         List<AttributeIfc> attributes = Lists.newArrayList();
-        // List<JavaAttribute> javaAttributes = new ArrayList<>();
-        // List<TOAttribute> toAttributes = new ArrayList<>();
         List<RuntimeBeanEntry> runtimeBeanEntries = new ArrayList<>();
         for (DataSchemaNode child : subtree.getChildNodes()) {
             // child leaves can be java attributes, TO attributes, or child
@@ -278,7 +276,7 @@ public class RuntimeBeanEntry {
                             .findJavaParameter(rpcDefinition);
                     AttributeIfc returnType;
                     if (rpcDefinition.getOutput() == null
-                            || rpcDefinition.getOutput().getChildNodes().size() == 0) {
+                            || rpcDefinition.getOutput().getChildNodes().isEmpty()) {
                         returnType = VoidAttribute.getInstance();
                     } else if (rpcDefinition.getOutput().getChildNodes().size() == 1) {
                         DataSchemaNode returnDSN = rpcDefinition.getOutput()
@@ -366,7 +364,7 @@ public class RuntimeBeanEntry {
                 currentModule, identitiesToRpcs);
 
         Optional<String> keyYangName;
-        if (listSchemaNode.getKeyDefinition().size() == 0) {
+        if (listSchemaNode.getKeyDefinition().isEmpty()) {
             keyYangName = Optional.absent();
         } else if (listSchemaNode.getKeyDefinition().size() == 1) {
             // key must be either null or one of supported key types
index ef40d9515b42c75ad3b6d6e56456ea83a1912688..ee02b303e0b2aa1778d2b45cffd421946411ae4f 100644 (file)
@@ -46,7 +46,7 @@ import static org.opendaylight.controller.config.yangjmxgenerator.ConfigConstant
  * </p>
  */
 public class ServiceInterfaceEntry extends AbstractEntry {
-    private static final Logger logger = LoggerFactory
+    private static final Logger LOGGER = LoggerFactory
             .getLogger(ServiceInterfaceEntry.class);
 
     private static final String CLASS_NAME_SUFFIX = "ServiceInterface";
@@ -121,16 +121,16 @@ public class ServiceInterfaceEntry extends AbstractEntry {
      */
     public static Map<QName, ServiceInterfaceEntry> create(Module currentModule,
             String packageName,Map<IdentitySchemaNode, ServiceInterfaceEntry> definedSEItracker) {
-        logger.debug("Generating ServiceInterfaces from {} to package {}",
+        LOGGER.debug("Generating ServiceInterfaces from {} to package {}",
                 currentModule.getNamespace(), packageName);
 
         Map<IdentitySchemaNode, ServiceInterfaceEntry> identitiesToSIs = new HashMap<>();
         Set<IdentitySchemaNode> notVisited = new HashSet<>(
                 currentModule.getIdentities());
         int lastSize = notVisited.size() + 1;
-        while (notVisited.size() > 0) {
+        while (!notVisited.isEmpty()) {
             if (notVisited.size() == lastSize) {
-                logger.debug(
+                LOGGER.debug(
                         "Following identities will be ignored while generating ServiceInterfaces, as they are not derived from {} : {}",
                         SERVICE_TYPE_Q_NAME, notVisited);
                 break;
@@ -175,7 +175,7 @@ public class ServiceInterfaceEntry extends AbstractEntry {
         for (ServiceInterfaceEntry sie : identitiesToSIs.values()) {
             resultMap.put(sie.getQName(), sie);
         }
-        logger.debug("Number of ServiceInterfaces to be generated: {}",
+        LOGGER.debug("Number of ServiceInterfaces to be generated: {}",
                 resultMap.size());
         return resultMap;
     }
@@ -198,25 +198,33 @@ public class ServiceInterfaceEntry extends AbstractEntry {
 
     @Override
     public boolean equals(Object o) {
-        if (this == o)
+        if (this == o) {
             return true;
-        if (o == null || getClass() != o.getClass())
+        }
+        if (o == null || getClass() != o.getClass()) {
             return false;
+        }
 
         ServiceInterfaceEntry that = (ServiceInterfaceEntry) o;
 
-        if (!maybeBaseCache.equals(that.maybeBaseCache))
+        if (!maybeBaseCache.equals(that.maybeBaseCache)) {
             return false;
-        if (!nullableDescription.equals(that.nullableDescription))
+        }
+        if (!nullableDescription.equals(that.nullableDescription)) {
             return false;
-        if (!exportedOsgiClassName.equals(that.exportedOsgiClassName))
+        }
+        if (!exportedOsgiClassName.equals(that.exportedOsgiClassName)) {
             return false;
-        if (!qName.equals(that.qName))
+        }
+        if (!qName.equals(that.qName)) {
             return false;
-        if (!packageName.equals(that.packageName))
+        }
+        if (!packageName.equals(that.packageName)) {
             return false;
-        if (!typeName.equals(that.typeName))
+        }
+        if (!typeName.equals(that.typeName)) {
             return false;
+        }
 
         return true;
     }
index 3c8c8aa2f4190af52f4484e1bda534c73d74eabb..ac1992932fe6c348920470b0c9e93004a49c5bf9 100644 (file)
@@ -71,9 +71,10 @@ public class TypeProviderWrapper {
         try {
             javaType = typeProvider.javaTypeForSchemaDefinitionType(
                     type, leaf);
-            if (javaType == null)
+            if (javaType == null) {
                 throw new IllegalArgumentException("Unknown type received for "
                         + leaf.toString());
+            }
         } catch (IllegalArgumentException e) {
             throw new IllegalArgumentException("Error while resolving type of "
                     + leaf, e);
@@ -87,9 +88,10 @@ public class TypeProviderWrapper {
         try {
             javaType = typeProvider.javaTypeForSchemaDefinitionType(
                     leaf.getType(), leaf);
-            if (javaType == null)
+            if (javaType == null) {
                 throw new IllegalArgumentException(
                         "Unknown type received for  " + leaf.toString());
+            }
         } catch (IllegalArgumentException e) {
             throw new IllegalArgumentException("Error while resolving type of "
                     + leaf, e);
index edfb4c59afe2c223685adeb487172ea85640a574..d9a6dd045214c4f01271703a8a3c4942cae33852 100644 (file)
@@ -33,17 +33,20 @@ public abstract class AbstractAttribute implements AttributeIfc {
 
     @Override
     public boolean equals(Object o) {
-        if (this == o)
+        if (this == o) {
             return true;
-        if (!(o instanceof AbstractAttribute))
+        }
+        if (!(o instanceof AbstractAttribute)) {
             return false;
+        }
 
         AbstractAttribute that = (AbstractAttribute) o;
 
         if (attributeYangName != null ? !attributeYangName
                 .equals(that.attributeYangName)
-                : that.attributeYangName != null)
+                : that.attributeYangName != null) {
             return false;
+        }
 
         return true;
     }
index eb1c9e41a6baf789b51a63a575e39cc9a16723ba..205ba893c4d7a4003875e08d7ab9a3aa2eb909a2 100644 (file)
@@ -40,25 +40,31 @@ public abstract class AbstractDependencyAttribute extends AbstractAttribute  imp
 
     @Override
     public boolean equals(Object o) {
-        if (this == o)
+        if (this == o) {
             return true;
-        if (o == null || getClass() != o.getClass())
+        }
+        if (o == null || getClass() != o.getClass()) {
             return false;
-        if (!super.equals(o))
+        }
+        if (!super.equals(o)) {
             return false;
+        }
 
         AbstractDependencyAttribute that = (AbstractDependencyAttribute) o;
 
         if (dependency != null ? !dependency.equals(that.dependency)
-                : that.dependency != null)
+                : that.dependency != null) {
             return false;
+        }
         if (nullableDefault != null ? !nullableDefault
-                .equals(that.nullableDefault) : that.nullableDefault != null)
+                .equals(that.nullableDefault) : that.nullableDefault != null) {
             return false;
+        }
         if (nullableDescription != null ? !nullableDescription
                 .equals(that.nullableDescription)
-                : that.nullableDescription != null)
+                : that.nullableDescription != null) {
             return false;
+        }
 
         return true;
     }
index fac4d5743229501fd7827269a8c810ac6b6f54a1..8d3139999e64db347e927dfa6dfc0e083c815a55 100644 (file)
@@ -96,24 +96,30 @@ public class JavaAttribute extends AbstractAttribute implements TypedAttribute {
 
     @Override
     public boolean equals(Object o) {
-        if (this == o)
+        if (this == o) {
             return true;
-        if (o == null || getClass() != o.getClass())
+        }
+        if (o == null || getClass() != o.getClass()) {
             return false;
-        if (!super.equals(o))
+        }
+        if (!super.equals(o)) {
             return false;
+        }
 
         JavaAttribute that = (JavaAttribute) o;
 
         if (nullableDefault != null ? !nullableDefault
-                .equals(that.nullableDefault) : that.nullableDefault != null)
+                .equals(that.nullableDefault) : that.nullableDefault != null) {
             return false;
+        }
         if (nullableDescription != null ? !nullableDescription
                 .equals(that.nullableDescription)
-                : that.nullableDescription != null)
+                : that.nullableDescription != null) {
             return false;
-        if (type != null ? !type.equals(that.type) : that.type != null)
+        }
+        if (type != null ? !type.equals(that.type) : that.type != null) {
             return false;
+        }
 
         return true;
     }
index 73b557e291c03385823fb214fb0a96054d2b6610..bb71f9dbc733da09c17e6be379bde458a0df7591 100644 (file)
@@ -82,22 +82,27 @@ public class ListAttribute extends AbstractAttribute implements TypedAttribute {
 
     @Override
     public boolean equals(Object o) {
-        if (this == o)
+        if (this == o) {
             return true;
-        if (o == null || getClass() != o.getClass())
+        }
+        if (o == null || getClass() != o.getClass()) {
             return false;
-        if (!super.equals(o))
+        }
+        if (!super.equals(o)) {
             return false;
+        }
 
         ListAttribute that = (ListAttribute) o;
 
         if (nullableDefault != null ? !nullableDefault
-                .equals(that.nullableDefault) : that.nullableDefault != null)
+                .equals(that.nullableDefault) : that.nullableDefault != null) {
             return false;
+        }
         if (nullableDescription != null ? !nullableDescription
                 .equals(that.nullableDescription)
-                : that.nullableDescription != null)
+                : that.nullableDescription != null) {
             return false;
+        }
 
         return true;
     }
index f4bd979faca43fa5f4bdce943ceeb389ca07b42b..9b5530175cf3e0d7165311d2d77d7f43c82681a8 100644 (file)
@@ -19,6 +19,9 @@ import java.util.Map;
 
 public class SimpleTypeResolver {
 
+    private SimpleTypeResolver() {
+    }
+
     public static SimpleType<?> getSimpleType(Type type) {
         SimpleType<?> expectedSimpleType = JAVA_TYPE_TO_SIMPLE_TYPE.get(type
                 .getFullyQualifiedName());
index cbeb5c3b297415bacf1a74596abbbf8d4fb9d207..e563da1328a210f82b44f498b08fd9c73348cfd3 100644 (file)
@@ -73,18 +73,19 @@ public class TOAttribute extends AbstractAttribute implements TypedAttribute {
             TypeProviderWrapper typeProviderWrapper, String packageName) {
         Class<? extends DataSchemaNode> type = isAllowedType(dataSchemaNode);
 
-        if (type.equals(LeafSchemaNode.class))
+        if (type.equals(LeafSchemaNode.class)) {
             return new JavaAttribute((LeafSchemaNode) dataSchemaNode,
                     typeProviderWrapper);
-        else if (type.equals(ListSchemaNode.class))
+        } else if (type.equals(ListSchemaNode.class)) {
             return ListAttribute.create((ListSchemaNode) dataSchemaNode,
                     typeProviderWrapper, packageName);
-        else if (type.equals(LeafListSchemaNode.class))
+        } else if (type.equals(LeafListSchemaNode.class)) {
             return ListAttribute.create((LeafListSchemaNode) dataSchemaNode,
                     typeProviderWrapper);
-        else if (type.equals(ContainerSchemaNode.class))
+        } else if (type.equals(ContainerSchemaNode.class)) {
             return TOAttribute.create((ContainerSchemaNode) dataSchemaNode,
                     typeProviderWrapper, packageName);
+        }
 
         throw new IllegalStateException("This should never happen");
     }
@@ -92,8 +93,9 @@ public class TOAttribute extends AbstractAttribute implements TypedAttribute {
     private static Class<? extends DataSchemaNode> isAllowedType(
             DataSchemaNode dataSchemaNode) {
         for (Class<? extends DataSchemaNode> allowedType : ALLOWED_CHILDREN) {
-            if (allowedType.isAssignableFrom(dataSchemaNode.getClass()) == true)
+            if (allowedType.isAssignableFrom(dataSchemaNode.getClass()) == true) {
                 return allowedType;
+            }
         }
         throw new IllegalArgumentException("Illegal child node for TO: "
                 + dataSchemaNode.getClass() + " allowed node types: "
@@ -156,26 +158,32 @@ public class TOAttribute extends AbstractAttribute implements TypedAttribute {
 
     @Override
     public boolean equals(Object o) {
-        if (this == o)
+        if (this == o) {
             return true;
-        if (o == null || getClass() != o.getClass())
+        }
+        if (o == null || getClass() != o.getClass()) {
             return false;
-        if (!super.equals(o))
+        }
+        if (!super.equals(o)) {
             return false;
+        }
 
         TOAttribute that = (TOAttribute) o;
 
         if (nullableDefault != null ? !nullableDefault
-                .equals(that.nullableDefault) : that.nullableDefault != null)
+                .equals(that.nullableDefault) : that.nullableDefault != null) {
             return false;
+        }
         if (nullableDescription != null ? !nullableDescription
                 .equals(that.nullableDescription)
-                : that.nullableDescription != null)
+                : that.nullableDescription != null) {
             return false;
+        }
         if (yangNameToAttributeMap != null ? !yangNameToAttributeMap
                 .equals(that.yangNameToAttributeMap)
-                : that.yangNameToAttributeMap != null)
+                : that.yangNameToAttributeMap != null) {
             return false;
+        }
 
         return true;
     }
index 30c7919c1a3cd89090ab168d8b848cb8e54b2af9..16c4bd1ec5ba76eaa3f5f19cdf3353cc94d153fe 100644 (file)
@@ -13,17 +13,19 @@ import java.util.Date;
 
 final class Util {
 
+    private Util() {
+    }
     /**
      * Used for date <-> xml serialization
      */
-    private static final SimpleDateFormat dateFormat = new SimpleDateFormat(
+    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat(
             "yyyy-MM-dd");
 
     public static String writeDate(Date date) {
-        return dateFormat.format(date);
+        return DATE_FORMAT.format(date);
     }
 
     public static Date readDate(String s) throws ParseException {
-        return dateFormat.parse(s);
+        return DATE_FORMAT.parse(s);
     }
 }
index 50b4485e01e947c2e9d6156c097b5d37d31e6fcc..966aff96a050ecc2ba0e48f1d6a27736ddd861d4 100644 (file)
@@ -8,6 +8,10 @@
 package org.opendaylight.controller.config.yangjmxgenerator.plugin.util;
 
 public class FullyQualifiedNameHelper {
+
+    private FullyQualifiedNameHelper() {
+    }
+
     public static String getFullyQualifiedName(String packageName,
             String className) {
         if (packageName.isEmpty())
index 1612f3434382655aa67bf0c732e9ca4eaacc4258..3a2f4b058020f86c3f20faaa5f5e61c4a558dfbb 100644 (file)
       <type>xml</type>
       <scope>runtime</scope>
     </dependency>
+    <!-- Netconf connector features. When this is included, users can test the netconf connector using netconf-testtool -->
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>features-netconf-connector</artifactId>
+      <classifier>features</classifier>
+      <type>xml</type>
+    </dependency>
+
   </dependencies>
 
   <build>
index 4fc0cf75b33702574f12ecb605d87d5392566086..6a8e3c0e5bc62ee437ce2661f755d288e4caab55 100644 (file)
@@ -7,9 +7,7 @@
  */
 package org.opendaylight.controller.sal.compatibility;
 
-import java.util.Dictionary;
-import java.util.Hashtable;
-
+import com.google.common.base.Preconditions;
 import org.apache.felix.dm.Component;
 import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
@@ -36,7 +34,8 @@ import org.opendaylight.controller.sal.utils.INodeConnectorFactory;
 import org.opendaylight.controller.sal.utils.INodeFactory;
 import org.osgi.framework.BundleContext;
 
-import com.google.common.base.Preconditions;
+import java.util.Dictionary;
+import java.util.Hashtable;
 
 public class ComponentActivator extends ComponentActivatorAbstractBase {
     private final INodeConnectorFactory nodeConnectorFactory = new MDSalNodeConnectorFactory();
@@ -90,8 +89,8 @@ public class ComponentActivator extends ComponentActivatorAbstractBase {
 
     @Override
     public void start(final BundleContext context) {
-        super.start(context);
         this.context = Preconditions.checkNotNull(context);
+        super.start(context);
     }
 
     public ProviderContext setBroker(final BindingAwareBroker broker) {
@@ -101,14 +100,14 @@ public class ComponentActivator extends ComponentActivatorAbstractBase {
     @Override
     protected Object[] getGlobalImplementations() {
         return new Object[] {
+                this, // Used for setBroker callback
                 flow,
                 inventory,
                 dataPacket,
                 nodeFactory,
                 nodeConnectorFactory,
                 topology,
-                tpProvider,
-                this // Used for setBroker callback
+                tpProvider
         };
     }
 
@@ -216,6 +215,9 @@ public class ComponentActivator extends ComponentActivatorAbstractBase {
                 .setService(IDiscoveryService.class)
                 .setCallbacks("setDiscoveryPublisher", "setDiscoveryPublisher")
                 .setRequired(false));
+        it.add(createServiceDependency()
+                .setService(BindingAwareBroker.class)
+                .setRequired(true));
     }
 
     private void _instanceConfigure(final InventoryAndReadAdapter imp, final Component it, String containerName) {
@@ -232,6 +234,9 @@ public class ComponentActivator extends ComponentActivatorAbstractBase {
                 .setService(IPluginOutInventoryService.class)
                 .setCallbacks("setInventoryPublisher", "unsetInventoryPublisher")
                 .setRequired(false));
+        it.add(createServiceDependency()
+                .setService(BindingAwareBroker.class)
+                .setRequired(true));
     }
 
     private void _configure(final TopologyAdapter imp, final Component it) {
diff --git a/opendaylight/md-sal/model/model-flow-service/src/main/yang/node-config.yang b/opendaylight/md-sal/model/model-flow-service/src/main/yang/node-config.yang
new file mode 100644 (file)
index 0000000..98c3228
--- /dev/null
@@ -0,0 +1,39 @@
+module node-config {
+    namespace "urn:opendaylight:module:config";
+    prefix node-config;
+
+    import flow-capable-transaction {prefix tr;}
+    import opendaylight-inventory {prefix inv;revision-date "2013-08-19";}
+
+    revision "2014-10-15" {
+        description "Initial revision of node configuration service";
+    }
+
+    grouping node-ref {
+        uses "inv:node-context-ref";
+    }
+
+
+
+    /** Base configuration structure **/
+    grouping node-config {
+        leaf flag {
+            type string;
+            description "Switch config flag. Expected values FRAGNORMAL, OFPCFRAGDROP, OFPCFRAGREASM, OFPCFRAGMASK";
+        }
+        leaf miss-search-length{
+            type uint16;
+        }
+    }
+
+    rpc set-config {
+        input {
+            uses node-config;
+            uses tr:transaction-aware;
+            uses node-ref;
+        }
+        output {
+            uses tr:transaction-aware;
+        }
+    }
+}
index 04df7785ad8d27c69e77f9e0cd85a5cbb64208b0..97b912ef74dcb1a78073999a06a8957c63c8eb47 100644 (file)
@@ -100,7 +100,7 @@ public class ExampleActor extends RaftActor {
         try {
             bs = fromObject(state);
         } catch (Exception e) {
-            LOG.error("Exception in creating snapshot", e);
+            LOG.error(e, "Exception in creating snapshot");
         }
         getSelf().tell(new CaptureSnapshotReply(bs), null);
     }
@@ -110,10 +110,10 @@ public class ExampleActor extends RaftActor {
         try {
             state.putAll((HashMap) toObject(snapshot));
         } catch (Exception e) {
-           LOG.error("Exception in applying snapshot", e);
+           LOG.error(e, "Exception in applying snapshot");
         }
         if(LOG.isDebugEnabled()) {
-            LOG.debug("Snapshot applied to state :" + ((HashMap) state).size());
+            LOG.debug("Snapshot applied to state : {}", ((HashMap) state).size());
         }
     }
 
index 64fa7496042466e58bd51cf0a488c265898866da..66a46ef3bde0ca8a8d1fa8fe1056ccb463a594d6 100644 (file)
@@ -29,9 +29,7 @@ import org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshot;
 import org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshotReply;
 import org.opendaylight.controller.cluster.raft.base.messages.Replicate;
 import org.opendaylight.controller.cluster.raft.base.messages.SendHeartBeat;
-import org.opendaylight.controller.cluster.raft.behaviors.Candidate;
 import org.opendaylight.controller.cluster.raft.behaviors.Follower;
-import org.opendaylight.controller.cluster.raft.behaviors.Leader;
 import org.opendaylight.controller.cluster.raft.behaviors.RaftActorBehavior;
 import org.opendaylight.controller.cluster.raft.client.messages.AddRaftPeer;
 import org.opendaylight.controller.cluster.raft.client.messages.FindLeader;
@@ -159,7 +157,9 @@ public abstract class RaftActor extends UntypedPersistentActor {
     }
 
     private void onRecoveredSnapshot(SnapshotOffer offer) {
-        LOG.debug("SnapshotOffer called..");
+        if(LOG.isDebugEnabled()) {
+            LOG.debug("SnapshotOffer called..");
+        }
 
         initRecoveryTimer();
 
@@ -250,7 +250,7 @@ public abstract class RaftActor extends UntypedPersistentActor {
             replicatedLog.lastIndex(), replicatedLog.snapshotIndex,
             replicatedLog.snapshotTerm, replicatedLog.size());
 
-        currentBehavior = switchBehavior(RaftState.Follower);
+        currentBehavior = new Follower(context);
         onStateChanged();
     }
 
@@ -355,14 +355,13 @@ public abstract class RaftActor extends UntypedPersistentActor {
             if (!(message instanceof AppendEntriesMessages.AppendEntries)
                 && !(message instanceof AppendEntriesReply) && !(message instanceof SendHeartBeat)) {
                 if(LOG.isDebugEnabled()) {
-                    LOG.debug("onReceiveCommand: message:" + message.getClass());
+                    LOG.debug("onReceiveCommand: message: {}", message.getClass());
                 }
             }
 
-            RaftState state =
-                currentBehavior.handleMessage(getSender(), message);
             RaftActorBehavior oldBehavior = currentBehavior;
-            currentBehavior = switchBehavior(state);
+            currentBehavior = currentBehavior.handleMessage(getSender(), message);
+
             if(oldBehavior != currentBehavior){
                 onStateChanged();
             }
@@ -569,38 +568,6 @@ public abstract class RaftActor extends UntypedPersistentActor {
 
     protected void onLeaderChanged(String oldLeader, String newLeader){};
 
-    private RaftActorBehavior switchBehavior(RaftState state) {
-        if (currentBehavior != null) {
-            if (currentBehavior.state() == state) {
-                return currentBehavior;
-            }
-            LOG.info("Switching from state " + currentBehavior.state() + " to "
-                + state);
-
-            try {
-                currentBehavior.close();
-            } catch (Exception e) {
-                LOG.error(e,
-                    "Failed to close behavior : " + currentBehavior.state());
-            }
-
-        } else {
-            LOG.info("Switching behavior to " + state);
-        }
-        RaftActorBehavior behavior = null;
-        if (state == RaftState.Candidate) {
-            behavior = new Candidate(context);
-        } else if (state == RaftState.Follower) {
-            behavior = new Follower(context);
-        } else {
-            behavior = new Leader(context);
-        }
-
-
-
-        return behavior;
-    }
-
     private void trimPersistentData(long sequenceNumber) {
         // Trim akka snapshots
         // FIXME : Not sure how exactly the SnapshotSelectionCriteria is applied
@@ -622,8 +589,8 @@ public abstract class RaftActor extends UntypedPersistentActor {
         }
         String peerAddress = context.getPeerAddress(leaderId);
         if(LOG.isDebugEnabled()) {
-            LOG.debug("getLeaderAddress leaderId = " + leaderId + " peerAddress = "
-                + peerAddress);
+            LOG.debug("getLeaderAddress leaderId = {} peerAddress = {}",
+                    leaderId, peerAddress);
         }
 
         return peerAddress;
@@ -697,8 +664,11 @@ public abstract class RaftActor extends UntypedPersistentActor {
         public void appendAndPersist(final ActorRef clientActor,
             final String identifier,
             final ReplicatedLogEntry replicatedLogEntry) {
-            context.getLogger().debug(
-                "Append log entry and persist {} ", replicatedLogEntry);
+
+            if(LOG.isDebugEnabled()) {
+                LOG.debug("Append log entry and persist {} ", replicatedLogEntry);
+            }
+
             // FIXME : By adding the replicated log entry to the in-memory journal we are not truly ensuring durability of the logs
             journal.add(replicatedLogEntry);
 
index b1560a5648b283e028ae0dc96e4267d92c6f438f..eed74bba82fbf8a4f8e4c1b5431887451c49d59d 100644 (file)
@@ -10,9 +10,9 @@ package org.opendaylight.controller.cluster.raft.behaviors;
 
 import akka.actor.ActorRef;
 import akka.actor.Cancellable;
+import akka.event.LoggingAdapter;
 import org.opendaylight.controller.cluster.raft.ClientRequestTracker;
 import org.opendaylight.controller.cluster.raft.RaftActorContext;
-import org.opendaylight.controller.cluster.raft.RaftState;
 import org.opendaylight.controller.cluster.raft.ReplicatedLogEntry;
 import org.opendaylight.controller.cluster.raft.SerializationUtils;
 import org.opendaylight.controller.cluster.raft.base.messages.ApplyLogEntries;
@@ -44,6 +44,11 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior {
      */
     protected final RaftActorContext context;
 
+    /**
+     *
+     */
+    protected final LoggingAdapter LOG;
+
     /**
      *
      */
@@ -57,6 +62,7 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior {
 
     protected AbstractRaftActorBehavior(RaftActorContext context) {
         this.context = context;
+        this.LOG = context.getLogger();
     }
 
     /**
@@ -71,7 +77,7 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior {
      * @param appendEntries  The AppendEntries message
      * @return
      */
-    protected abstract RaftState handleAppendEntries(ActorRef sender,
+    protected abstract RaftActorBehavior handleAppendEntries(ActorRef sender,
         AppendEntries appendEntries);
 
 
@@ -83,19 +89,21 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior {
      * @param appendEntries
      * @return
      */
-    protected RaftState appendEntries(ActorRef sender,
+    protected RaftActorBehavior appendEntries(ActorRef sender,
         AppendEntries appendEntries) {
 
         // 1. Reply false if term < currentTerm (§5.1)
         if (appendEntries.getTerm() < currentTerm()) {
-            context.getLogger().debug(
-                "Cannot append entries because sender term " + appendEntries
-                    .getTerm() + " is less than " + currentTerm());
+            if(LOG.isDebugEnabled()) {
+                LOG.debug("Cannot append entries because sender term {} is less than {}",
+                        appendEntries.getTerm(), currentTerm());
+            }
+
             sender.tell(
                 new AppendEntriesReply(context.getId(), currentTerm(), false,
                     lastIndex(), lastTerm()), actor()
             );
-            return state();
+            return this;
         }
 
 
@@ -114,7 +122,7 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior {
      * @param appendEntriesReply The AppendEntriesReply message
      * @return
      */
-    protected abstract RaftState handleAppendEntriesReply(ActorRef sender,
+    protected abstract RaftActorBehavior handleAppendEntriesReply(ActorRef sender,
         AppendEntriesReply appendEntriesReply);
 
     /**
@@ -125,11 +133,12 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior {
      * @param requestVote
      * @return
      */
-    protected RaftState requestVote(ActorRef sender,
+    protected RaftActorBehavior requestVote(ActorRef sender,
         RequestVote requestVote) {
 
-
-        context.getLogger().debug(requestVote.toString());
+        if(LOG.isDebugEnabled()) {
+            LOG.debug(requestVote.toString());
+        }
 
         boolean grantVote = false;
 
@@ -167,7 +176,7 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior {
 
         sender.tell(new RequestVoteReply(currentTerm(), grantVote), actor());
 
-        return state();
+        return this;
     }
 
     /**
@@ -182,7 +191,7 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior {
      * @param requestVoteReply The RequestVoteReply message
      * @return
      */
-    protected abstract RaftState handleRequestVoteReply(ActorRef sender,
+    protected abstract RaftActorBehavior handleRequestVoteReply(ActorRef sender,
         RequestVoteReply requestVoteReply);
 
     /**
@@ -341,12 +350,14 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior {
             } else {
                 //if one index is not present in the log, no point in looping
                 // around as the rest wont be present either
-                context.getLogger().warning(
-                    "Missing index {} from log. Cannot apply state. Ignoring {} to {}", i, i, index );
+                LOG.warning(
+                        "Missing index {} from log. Cannot apply state. Ignoring {} to {}", i, i, index);
                 break;
             }
         }
-        context.getLogger().debug("Setting last applied to {}", newLastApplied);
+        if(LOG.isDebugEnabled()) {
+            LOG.debug("Setting last applied to {}", newLastApplied);
+        }
         context.setLastApplied(newLastApplied);
 
         // send a message to persist a ApplyLogEntries marker message into akka's persistent journal
@@ -361,7 +372,7 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior {
     }
 
     @Override
-    public RaftState handleMessage(ActorRef sender, Object message) {
+    public RaftActorBehavior handleMessage(ActorRef sender, Object message) {
         if (message instanceof AppendEntries) {
             return appendEntries(sender, (AppendEntries) message);
         } else if (message instanceof AppendEntriesReply) {
@@ -371,10 +382,21 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior {
         } else if (message instanceof RequestVoteReply) {
             return handleRequestVoteReply(sender, (RequestVoteReply) message);
         }
-        return state();
+        return this;
     }
 
     @Override public String getLeaderId() {
         return leaderId;
     }
+
+    protected RaftActorBehavior switchBehavior(RaftActorBehavior behavior) {
+        LOG.info("Switching from behavior {} to {}", this.state(), behavior.state());
+        try {
+            close();
+        } catch (Exception e) {
+            LOG.error(e, "Failed to close behavior : {}", this.state());
+        }
+
+        return behavior;
+    }
 }
index bb1927ef231949bd320d0cf060d6a9a8018829bb..4a3e2c5d664406844edaddee6308abf112b0f79c 100644 (file)
@@ -52,7 +52,9 @@ public class Candidate extends AbstractRaftActorBehavior {
 
         peers = context.getPeerAddresses().keySet();
 
-        context.getLogger().debug("Election:Candidate has following peers:"+ peers);
+        if(LOG.isDebugEnabled()) {
+            LOG.debug("Election:Candidate has following peers: {}", peers);
+        }
 
         if(peers.size() > 0) {
             // Votes are required from a majority of the peers including self.
@@ -78,21 +80,23 @@ public class Candidate extends AbstractRaftActorBehavior {
         scheduleElection(electionDuration());
     }
 
-    @Override protected RaftState handleAppendEntries(ActorRef sender,
+    @Override protected RaftActorBehavior handleAppendEntries(ActorRef sender,
         AppendEntries appendEntries) {
 
-        context.getLogger().debug(appendEntries.toString());
+        if(LOG.isDebugEnabled()) {
+            LOG.debug(appendEntries.toString());
+        }
 
-        return state();
+        return this;
     }
 
-    @Override protected RaftState handleAppendEntriesReply(ActorRef sender,
+    @Override protected RaftActorBehavior handleAppendEntriesReply(ActorRef sender,
         AppendEntriesReply appendEntriesReply) {
 
-        return state();
+        return this;
     }
 
-    @Override protected RaftState handleRequestVoteReply(ActorRef sender,
+    @Override protected RaftActorBehavior handleRequestVoteReply(ActorRef sender,
         RequestVoteReply requestVoteReply) {
 
         if (requestVoteReply.isVoteGranted()) {
@@ -100,10 +104,10 @@ public class Candidate extends AbstractRaftActorBehavior {
         }
 
         if (voteCount >= votesRequired) {
-            return RaftState.Leader;
+            return switchBehavior(new Leader(context));
         }
 
-        return state();
+        return this;
     }
 
     @Override public RaftState state() {
@@ -111,7 +115,7 @@ public class Candidate extends AbstractRaftActorBehavior {
     }
 
     @Override
-    public RaftState handleMessage(ActorRef sender, Object originalMessage) {
+    public RaftActorBehavior handleMessage(ActorRef sender, Object originalMessage) {
 
         Object message = fromSerializableMessage(originalMessage);
 
@@ -119,14 +123,17 @@ public class Candidate extends AbstractRaftActorBehavior {
 
             RaftRPC rpc = (RaftRPC) message;
 
-            context.getLogger().debug("RaftRPC message received {} my term is {}", rpc.toString(), context.getTermInformation().getCurrentTerm());
+            if(LOG.isDebugEnabled()) {
+                LOG.debug("RaftRPC message received {} my term is {}", rpc, context.getTermInformation().getCurrentTerm());
+            }
 
             // If RPC request or response contains term T > currentTerm:
             // set currentTerm = T, convert to follower (§5.1)
             // This applies to all RPC messages and responses
             if (rpc.getTerm() > context.getTermInformation().getCurrentTerm()) {
                 context.getTermInformation().updateAndPersist(rpc.getTerm(), null);
-                return RaftState.Follower;
+
+                return switchBehavior(new Follower(context));
             }
         }
 
@@ -137,11 +144,12 @@ public class Candidate extends AbstractRaftActorBehavior {
                 // ourselves the leader. This gives enough time for a leader
                 // who we do not know about (as a peer)
                 // to send a message to the candidate
-                return RaftState.Leader;
+
+                return switchBehavior(new Leader(context));
             }
             startNewTerm();
             scheduleElection(electionDuration());
-            return state();
+            return this;
         }
 
         return super.handleMessage(sender, message);
@@ -159,7 +167,9 @@ public class Candidate extends AbstractRaftActorBehavior {
         context.getTermInformation().updateAndPersist(currentTerm + 1,
             context.getId());
 
-        context.getLogger().debug("Starting new term " + (currentTerm + 1));
+        if(LOG.isDebugEnabled()) {
+            LOG.debug("Starting new term {}", (currentTerm + 1));
+        }
 
         // Request for a vote
         // TODO: Retry request for vote if replies do not arrive in a reasonable
index 1cfdf9dba8b912a5bc23f78b85c447621298d908..7ada8b31c54f75c9c8f8dc9ce3456260d77af80a 100644 (file)
@@ -9,7 +9,6 @@
 package org.opendaylight.controller.cluster.raft.behaviors;
 
 import akka.actor.ActorRef;
-import akka.event.LoggingAdapter;
 import com.google.protobuf.ByteString;
 import org.opendaylight.controller.cluster.raft.RaftActorContext;
 import org.opendaylight.controller.cluster.raft.RaftState;
@@ -39,17 +38,13 @@ import java.util.ArrayList;
 public class Follower extends AbstractRaftActorBehavior {
     private ByteString snapshotChunksCollected = ByteString.EMPTY;
 
-    private final LoggingAdapter LOG;
-
     public Follower(RaftActorContext context) {
         super(context);
 
-        LOG = context.getLogger();
-
         scheduleElection(electionDuration());
     }
 
-    @Override protected RaftState handleAppendEntries(ActorRef sender,
+    @Override protected RaftActorBehavior handleAppendEntries(ActorRef sender,
         AppendEntries appendEntries) {
 
         if(appendEntries.getEntries() != null && appendEntries.getEntries().size() > 0) {
@@ -133,15 +128,14 @@ public class Follower extends AbstractRaftActorBehavior {
                 new AppendEntriesReply(context.getId(), currentTerm(), false,
                     lastIndex(), lastTerm()), actor()
             );
-            return state();
+            return this;
         }
 
         if (appendEntries.getEntries() != null
             && appendEntries.getEntries().size() > 0) {
             if(LOG.isDebugEnabled()) {
                 LOG.debug(
-                    "Number of entries to be appended = " + appendEntries
-                        .getEntries().size()
+                    "Number of entries to be appended = {}", appendEntries.getEntries().size()
                 );
             }
 
@@ -168,8 +162,7 @@ public class Follower extends AbstractRaftActorBehavior {
 
                     if(LOG.isDebugEnabled()) {
                         LOG.debug(
-                            "Removing entries from log starting at "
-                                + matchEntry.getIndex()
+                            "Removing entries from log starting at {}", matchEntry.getIndex()
                         );
                     }
 
@@ -181,9 +174,7 @@ public class Follower extends AbstractRaftActorBehavior {
             }
 
             if(LOG.isDebugEnabled()) {
-                context.getLogger().debug(
-                    "After cleanup entries to be added from = " + (addEntriesFrom
-                        + lastIndex())
+                LOG.debug("After cleanup entries to be added from = {}", (addEntriesFrom + lastIndex())
                 );
             }
 
@@ -191,17 +182,14 @@ public class Follower extends AbstractRaftActorBehavior {
             for (int i = addEntriesFrom;
                  i < appendEntries.getEntries().size(); i++) {
 
-                context.getLogger().info(
-                    "Append entry to log " + appendEntries.getEntries().get(
-                        i).getData()
-                        .toString()
-                );
-                context.getReplicatedLog()
-                    .appendAndPersist(appendEntries.getEntries().get(i));
+                if(LOG.isDebugEnabled()) {
+                    LOG.debug("Append entry to log {}", appendEntries.getEntries().get(i).getData());
+                }
+                context.getReplicatedLog().appendAndPersist(appendEntries.getEntries().get(i));
             }
 
             if(LOG.isDebugEnabled()) {
-                LOG.debug("Log size is now " + context.getReplicatedLog().size());
+                LOG.debug("Log size is now {}", context.getReplicatedLog().size());
             }
         }
 
@@ -216,7 +204,7 @@ public class Follower extends AbstractRaftActorBehavior {
 
         if (prevCommitIndex != context.getCommitIndex()) {
             if(LOG.isDebugEnabled()) {
-                LOG.debug("Commit index set to " + context.getCommitIndex());
+                LOG.debug("Commit index set to {}", context.getCommitIndex());
             }
         }
 
@@ -239,24 +227,24 @@ public class Follower extends AbstractRaftActorBehavior {
         sender.tell(new AppendEntriesReply(context.getId(), currentTerm(), true,
             lastIndex(), lastTerm()), actor());
 
-        return state();
+        return this;
     }
 
-    @Override protected RaftState handleAppendEntriesReply(ActorRef sender,
+    @Override protected RaftActorBehavior handleAppendEntriesReply(ActorRef sender,
         AppendEntriesReply appendEntriesReply) {
-        return state();
+        return this;
     }
 
-    @Override protected RaftState handleRequestVoteReply(ActorRef sender,
+    @Override protected RaftActorBehavior handleRequestVoteReply(ActorRef sender,
         RequestVoteReply requestVoteReply) {
-        return state();
+        return this;
     }
 
     @Override public RaftState state() {
         return RaftState.Follower;
     }
 
-    @Override public RaftState handleMessage(ActorRef sender, Object originalMessage) {
+    @Override public RaftActorBehavior handleMessage(ActorRef sender, Object originalMessage) {
 
         Object message = fromSerializableMessage(originalMessage);
 
@@ -271,7 +259,7 @@ public class Follower extends AbstractRaftActorBehavior {
         }
 
         if (message instanceof ElectionTimeout) {
-            return RaftState.Candidate;
+            return switchBehavior(new Candidate(context));
 
         } else if (message instanceof InstallSnapshot) {
             InstallSnapshot installSnapshot = (InstallSnapshot) message;
@@ -297,8 +285,10 @@ public class Follower extends AbstractRaftActorBehavior {
                 // 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());
+                if(LOG.isDebugEnabled()) {
+                    LOG.debug("Last chunk received: snapshotChunksCollected.size:{}",
+                            snapshotChunksCollected.size());
+                }
 
                 Snapshot snapshot = Snapshot.create(snapshotChunksCollected.toByteArray(),
                     new ArrayList<ReplicatedLogEntry>(),
@@ -324,7 +314,7 @@ public class Follower extends AbstractRaftActorBehavior {
                 true), actor());
 
         } catch (Exception e) {
-            context.getLogger().error("Exception in InstallSnapshot of follower", e);
+            LOG.error(e, "Exception in InstallSnapshot of follower:");
             //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());
index ff8a2256d3cb05a7f29a99f6741aa4948935145b..9edba85865e87a0351ca14154f4665fe935f75d2 100644 (file)
@@ -11,7 +11,6 @@ package org.opendaylight.controller.cluster.raft.behaviors;
 import akka.actor.ActorRef;
 import akka.actor.ActorSelection;
 import akka.actor.Cancellable;
-import akka.event.LoggingAdapter;
 import com.google.common.base.Preconditions;
 import com.google.protobuf.ByteString;
 import org.opendaylight.controller.cluster.raft.ClientRequestTracker;
@@ -81,13 +80,9 @@ public class Leader extends AbstractRaftActorBehavior {
 
     private final int minReplicationCount;
 
-    private final LoggingAdapter LOG;
-
     public Leader(RaftActorContext context) {
         super(context);
 
-        LOG = context.getLogger();
-
         followers = context.getPeerAddresses().keySet();
 
         for (String followerId : followers) {
@@ -100,7 +95,7 @@ public class Leader extends AbstractRaftActorBehavior {
         }
 
         if(LOG.isDebugEnabled()) {
-            LOG.debug("Election:Leader has following peers:" + followers);
+            LOG.debug("Election:Leader has following peers: {}", followers);
         }
 
         if (followers.size() > 0) {
@@ -123,17 +118,17 @@ public class Leader extends AbstractRaftActorBehavior {
 
     }
 
-    @Override protected RaftState handleAppendEntries(ActorRef sender,
+    @Override protected RaftActorBehavior handleAppendEntries(ActorRef sender,
         AppendEntries appendEntries) {
 
         if(LOG.isDebugEnabled()) {
             LOG.debug(appendEntries.toString());
         }
 
-        return state();
+        return this;
     }
 
-    @Override protected RaftState handleAppendEntriesReply(ActorRef sender,
+    @Override protected RaftActorBehavior handleAppendEntriesReply(ActorRef sender,
         AppendEntriesReply appendEntriesReply) {
 
         if(! appendEntriesReply.isSuccess()) {
@@ -149,7 +144,7 @@ public class Leader extends AbstractRaftActorBehavior {
 
         if(followerLogInformation == null){
             LOG.error("Unknown follower {}", followerId);
-            return state();
+            return this;
         }
 
         if (appendEntriesReply.isSuccess()) {
@@ -199,7 +194,7 @@ public class Leader extends AbstractRaftActorBehavior {
             applyLogToStateMachine(context.getCommitIndex());
         }
 
-        return state();
+        return this;
     }
 
     protected ClientRequestTracker removeClientRequestTracker(long logIndex) {
@@ -222,16 +217,16 @@ public class Leader extends AbstractRaftActorBehavior {
         return null;
     }
 
-    @Override protected RaftState handleRequestVoteReply(ActorRef sender,
+    @Override protected RaftActorBehavior handleRequestVoteReply(ActorRef sender,
         RequestVoteReply requestVoteReply) {
-        return state();
+        return this;
     }
 
     @Override public RaftState state() {
         return RaftState.Leader;
     }
 
-    @Override public RaftState handleMessage(ActorRef sender, Object originalMessage) {
+    @Override public RaftActorBehavior handleMessage(ActorRef sender, Object originalMessage) {
         Preconditions.checkNotNull(sender, "sender should not be null");
 
         Object message = fromSerializableMessage(originalMessage);
@@ -243,13 +238,15 @@ public class Leader extends AbstractRaftActorBehavior {
             // This applies to all RPC messages and responses
             if (rpc.getTerm() > context.getTermInformation().getCurrentTerm()) {
                 context.getTermInformation().updateAndPersist(rpc.getTerm(), null);
-                return RaftState.Follower;
+
+                return switchBehavior(new Follower(context));
             }
         }
 
         try {
             if (message instanceof SendHeartBeat) {
-                return sendHeartBeat();
+                sendHeartBeat();
+                return this;
             } else if(message instanceof SendInstallSnapshot) {
                 installSnapshotIfNeeded();
             } else if (message instanceof Replicate) {
@@ -321,7 +318,7 @@ public class Leader extends AbstractRaftActorBehavior {
         long logIndex = replicate.getReplicatedLogEntry().getIndex();
 
         if(LOG.isDebugEnabled()) {
-            LOG.debug("Replicate message " + logIndex);
+            LOG.debug("Replicate message {}", logIndex);
         }
 
         // Create a tracker entry we will use this later to notify the
@@ -445,7 +442,7 @@ public class Leader extends AbstractRaftActorBehavior {
                 followerActor.path(), mapFollowerToSnapshot.get(followerId).getChunkIndex(),
                 mapFollowerToSnapshot.get(followerId).getTotalChunks());
         } catch (IOException e) {
-            LOG.error("InstallSnapshot failed for Leader.", e);
+            LOG.error(e, "InstallSnapshot failed for Leader.");
         }
     }
 
@@ -467,11 +464,10 @@ public class Leader extends AbstractRaftActorBehavior {
         return nextChunk;
     }
 
-    private RaftState sendHeartBeat() {
+    private void sendHeartBeat() {
         if (followers.size() > 0) {
             sendAppendEntries();
         }
-        return state();
     }
 
     private void stopHeartBeat() {
index ca2d916ecf619ae61b8b627c2e10181d075a187a..064cd8b88c8b68152f04cdc25378c792eb263a7b 100644 (file)
@@ -25,17 +25,18 @@ import org.opendaylight.controller.cluster.raft.RaftState;
  * differently.
  */
 public interface RaftActorBehavior extends AutoCloseable{
+
     /**
      * Handle a message. If the processing of the message warrants a state
-     * change then a new state should be returned otherwise this method should
-     * return the state for the current behavior.
+     * change then a new behavior should be returned otherwise this method should
+     * return the current behavior.
      *
      * @param sender The sender of the message
      * @param message A message that needs to be processed
      *
-     * @return The new state or self (this)
+     * @return The new behavior or current behavior
      */
-    RaftState handleMessage(ActorRef sender, Object message);
+    RaftActorBehavior handleMessage(ActorRef sender, Object message);
 
     /**
      * The state associated with a given behavior
index 22f374319cfdbca12115fad320949c7b277a45a5..c15c9198bd17c2a3da0fa54b017379a5e8971b13 100644 (file)
@@ -181,7 +181,7 @@ public class RaftActorTest extends AbstractActorTest {
                         return true;
                     }
                 }.from(raftActor.path().toString())
-                    .message("Switching from state Candidate to Leader")
+                    .message("Switching from behavior Candidate to Leader")
                     .occurrences(1).exec();
 
 
index 8068dfbcff48970ad7203c43aae378eac4803851..38930180082fdcb80958c1b9adbe04f5062769bf 100644 (file)
@@ -7,7 +7,6 @@ import org.junit.Test;
 import org.opendaylight.controller.cluster.raft.AbstractActorTest;
 import org.opendaylight.controller.cluster.raft.MockRaftActorContext;
 import org.opendaylight.controller.cluster.raft.RaftActorContext;
-import org.opendaylight.controller.cluster.raft.RaftState;
 import org.opendaylight.controller.cluster.raft.ReplicatedLogEntry;
 import org.opendaylight.controller.cluster.raft.SerializationUtils;
 import org.opendaylight.controller.cluster.raft.messages.AppendEntries;
@@ -22,6 +21,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest {
 
@@ -79,12 +79,12 @@ public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest {
             RaftActorBehavior behavior = createBehavior(context);
 
             // Send an unknown message so that the state of the RaftActor remains unchanged
-            RaftState expected = behavior.handleMessage(getRef(), "unknown");
+            RaftActorBehavior expected = behavior.handleMessage(getRef(), "unknown");
 
-            RaftState raftState =
+            RaftActorBehavior raftBehavior =
                 behavior.handleMessage(getRef(), appendEntries);
 
-            assertEquals(expected, raftState);
+            assertEquals(expected, raftBehavior);
 
             // Also expect an AppendEntriesReply to be sent where success is false
             final Boolean out = new ExpectMsg<Boolean>(duration("1 seconds"),
@@ -145,12 +145,12 @@ public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest {
                 }
 
                 // Send an unknown message so that the state of the RaftActor remains unchanged
-                RaftState expected = behavior.handleMessage(getRef(), "unknown");
+                RaftActorBehavior expected = behavior.handleMessage(getRef(), "unknown");
 
-                RaftState raftState =
+                RaftActorBehavior raftBehavior =
                     behavior.handleMessage(getRef(), appendEntries);
 
-                assertEquals(expected, raftState);
+                assertEquals(expected, raftBehavior);
 
                 assertEquals(1, log.size());
 
@@ -174,11 +174,11 @@ public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest {
                     RaftActorBehavior behavior = createBehavior(
                         createActorContext(behaviorActor));
 
-                    RaftState raftState = behavior.handleMessage(getTestActor(),
+                    RaftActorBehavior raftBehavior = behavior.handleMessage(getTestActor(),
                         new RequestVote(1000, "test", 10000, 999));
 
-                    if(behavior.state() != RaftState.Follower){
-                        assertEquals(RaftState.Follower, raftState);
+                    if(!(behavior instanceof Follower)){
+                        assertTrue(raftBehavior instanceof Follower);
                     } else {
 
                         final Boolean out =
@@ -228,11 +228,11 @@ public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest {
 
                     RaftActorBehavior behavior = createBehavior(actorContext);
 
-                    RaftState raftState = behavior.handleMessage(getTestActor(),
+                    RaftActorBehavior raftBehavior = behavior.handleMessage(getTestActor(),
                         new RequestVote(1000, "test", 10000, 999));
 
-                    if(behavior.state() != RaftState.Follower){
-                        assertEquals(RaftState.Follower, raftState);
+                    if(!(behavior instanceof Follower)){
+                        assertTrue(raftBehavior instanceof Follower);
                     } else {
                         final Boolean out =
                             new ExpectMsg<Boolean>(duration("1 seconds"),
@@ -309,10 +309,10 @@ public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest {
         setLastLogEntry(
             (MockRaftActorContext) actorContext, 0, 0, p);
 
-        RaftState raftState = createBehavior(actorContext)
+        RaftActorBehavior raftBehavior = createBehavior(actorContext)
             .handleMessage(actorRef, rpc);
 
-        assertEquals(RaftState.Follower, raftState);
+        assertTrue(raftBehavior instanceof Follower);
     }
 
     protected MockRaftActorContext.SimpleReplicatedLog setLastLogEntry(
index d478b175550ba223a778fcf4121f36b9b41fbc1f..a8d47e2c60239a9a7f796a5afe93f7df0ef57d96 100644 (file)
@@ -9,7 +9,6 @@ import org.junit.Test;
 import org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl;
 import org.opendaylight.controller.cluster.raft.MockRaftActorContext;
 import org.opendaylight.controller.cluster.raft.RaftActorContext;
-import org.opendaylight.controller.cluster.raft.RaftState;
 import org.opendaylight.controller.cluster.raft.base.messages.ElectionTimeout;
 import org.opendaylight.controller.cluster.raft.messages.AppendEntries;
 import org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply;
@@ -109,10 +108,10 @@ public class CandidateTest extends AbstractRaftActorBehaviorTest {
         Candidate candidate =
             new Candidate(raftActorContext);
 
-        RaftState raftState =
+        RaftActorBehavior raftBehavior =
             candidate.handleMessage(candidateActor, new ElectionTimeout());
 
-        Assert.assertEquals(RaftState.Leader, raftState);
+        Assert.assertTrue(raftBehavior instanceof Leader);
     }
 
     @Test
@@ -123,10 +122,10 @@ public class CandidateTest extends AbstractRaftActorBehaviorTest {
         Candidate candidate =
             new Candidate(raftActorContext);
 
-        RaftState raftState =
+        RaftActorBehavior raftBehavior =
             candidate.handleMessage(candidateActor, new ElectionTimeout());
 
-        Assert.assertEquals(RaftState.Candidate, raftState);
+        Assert.assertTrue(raftBehavior instanceof Candidate);
     }
 
     @Test
@@ -137,9 +136,9 @@ public class CandidateTest extends AbstractRaftActorBehaviorTest {
         Candidate candidate =
             new Candidate(raftActorContext);
 
-        RaftState stateOnFirstVote = candidate.handleMessage(peerActor1, new RequestVoteReply(0, true));
+        RaftActorBehavior behaviorOnFirstVote = candidate.handleMessage(peerActor1, new RequestVoteReply(0, true));
 
-        Assert.assertEquals(RaftState.Leader, stateOnFirstVote);
+        Assert.assertTrue(behaviorOnFirstVote instanceof Leader);
 
     }
 
@@ -151,12 +150,12 @@ public class CandidateTest extends AbstractRaftActorBehaviorTest {
         Candidate candidate =
             new Candidate(raftActorContext);
 
-        RaftState stateOnFirstVote = candidate.handleMessage(peerActor1, new RequestVoteReply(0, true));
+        RaftActorBehavior behaviorOnFirstVote = candidate.handleMessage(peerActor1, new RequestVoteReply(0, true));
 
-        RaftState stateOnSecondVote = candidate.handleMessage(peerActor2, new RequestVoteReply(0, true));
+        RaftActorBehavior behaviorOnSecondVote = candidate.handleMessage(peerActor2, new RequestVoteReply(0, true));
 
-        Assert.assertEquals(RaftState.Candidate, stateOnFirstVote);
-        Assert.assertEquals(RaftState.Leader, stateOnSecondVote);
+        Assert.assertTrue(behaviorOnFirstVote instanceof Candidate);
+        Assert.assertTrue(behaviorOnSecondVote instanceof Leader);
 
     }
 
index a72a7c43324922748cad1837df047000cb1a4013..edeab11e2a6421cfdbafc7661ddca1e5b059ac7c 100644 (file)
@@ -9,7 +9,6 @@ import org.junit.Test;
 import org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl;
 import org.opendaylight.controller.cluster.raft.MockRaftActorContext;
 import org.opendaylight.controller.cluster.raft.RaftActorContext;
-import org.opendaylight.controller.cluster.raft.RaftState;
 import org.opendaylight.controller.cluster.raft.ReplicatedLogEntry;
 import org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot;
 import org.opendaylight.controller.cluster.raft.base.messages.ElectionTimeout;
@@ -85,10 +84,10 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest {
         Follower follower =
             new Follower(raftActorContext);
 
-        RaftState raftState =
+        RaftActorBehavior raftBehavior =
             follower.handleMessage(followerActor, new ElectionTimeout());
 
-        Assert.assertEquals(RaftState.Candidate, raftState);
+        Assert.assertTrue(raftBehavior instanceof Candidate);
     }
 
     @Test
@@ -187,7 +186,7 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest {
             AppendEntries appendEntries =
                 new AppendEntries(2, "leader-1", 100, 1, entries, 101);
 
-            RaftState raftState =
+            RaftActorBehavior raftBehavior =
                 createBehavior(context).handleMessage(getRef(), appendEntries);
 
             assertEquals(101L, context.getLastApplied());
@@ -226,12 +225,12 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest {
             RaftActorBehavior behavior = createBehavior(context);
 
             // Send an unknown message so that the state of the RaftActor remains unchanged
-            RaftState expected = behavior.handleMessage(getRef(), "unknown");
+            RaftActorBehavior expected = behavior.handleMessage(getRef(), "unknown");
 
-            RaftState raftState =
+            RaftActorBehavior raftBehavior =
                 behavior.handleMessage(getRef(), appendEntries);
 
-            assertEquals(expected, raftState);
+            assertEquals(expected, raftBehavior);
 
             // Also expect an AppendEntriesReply to be sent where success is false
             final Boolean out = new ExpectMsg<Boolean>(duration("1 seconds"),
@@ -302,12 +301,12 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest {
             RaftActorBehavior behavior = createBehavior(context);
 
             // Send an unknown message so that the state of the RaftActor remains unchanged
-            RaftState expected = behavior.handleMessage(getRef(), "unknown");
+            RaftActorBehavior expected = behavior.handleMessage(getRef(), "unknown");
 
-            RaftState raftState =
+            RaftActorBehavior raftBehavior =
                 behavior.handleMessage(getRef(), appendEntries);
 
-            assertEquals(expected, raftState);
+            assertEquals(expected, raftBehavior);
             assertEquals(5, log.last().getIndex() + 1);
             assertNotNull(log.get(3));
             assertNotNull(log.get(4));
@@ -382,12 +381,12 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest {
             RaftActorBehavior behavior = createBehavior(context);
 
             // Send an unknown message so that the state of the RaftActor remains unchanged
-            RaftState expected = behavior.handleMessage(getRef(), "unknown");
+            RaftActorBehavior expected = behavior.handleMessage(getRef(), "unknown");
 
-            RaftState raftState =
+            RaftActorBehavior raftBehavior =
                 behavior.handleMessage(getRef(), appendEntries);
 
-            assertEquals(expected, raftState);
+            assertEquals(expected, raftBehavior);
 
             // The entry at index 2 will be found out-of-sync with the leader
             // and will be removed
index 19af64790ff7896f496f6585aa27939d76fa4f65..48543d7de2178e937a82d31e03b71282ffdcb88b 100644 (file)
@@ -12,7 +12,6 @@ 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;
@@ -54,8 +53,8 @@ public class LeaderTest extends AbstractRaftActorBehaviorTest {
 
             // handle message should return the Leader state when it receives an
             // unknown message
-            RaftState state = leader.handleMessage(senderActor, "foo");
-            Assert.assertEquals(RaftState.Leader, state);
+            RaftActorBehavior behavior = leader.handleMessage(senderActor, "foo");
+            Assert.assertTrue(behavior instanceof Leader);
         }};
     }
 
@@ -125,7 +124,7 @@ public class LeaderTest extends AbstractRaftActorBehaviorTest {
                     actorContext.setPeerAddresses(peerAddresses);
 
                     Leader leader = new Leader(actorContext);
-                    RaftState raftState = leader
+                    RaftActorBehavior raftBehavior = leader
                         .handleMessage(senderActor, new Replicate(null, null,
                             new MockRaftActorContext.MockReplicatedLogEntry(1,
                                 100,
@@ -133,7 +132,7 @@ public class LeaderTest extends AbstractRaftActorBehaviorTest {
                         ));
 
                     // State should not change
-                    assertEquals(RaftState.Leader, raftState);
+                    assertTrue(raftBehavior instanceof Leader);
 
                     final String out =
                         new ExpectMsg<String>(duration("1 seconds"), "match hint") {
@@ -179,11 +178,11 @@ public class LeaderTest extends AbstractRaftActorBehaviorTest {
                             .build());
 
                     Leader leader = new Leader(actorContext);
-                    RaftState raftState = leader
+                    RaftActorBehavior raftBehavior = leader
                         .handleMessage(senderActor, new Replicate(null, "state-id",actorContext.getReplicatedLog().get(1)));
 
                     // State should not change
-                    assertEquals(RaftState.Leader, raftState);
+                    assertTrue(raftBehavior instanceof Leader);
 
                     assertEquals(1, actorContext.getCommitIndex());
 
@@ -258,10 +257,10 @@ public class LeaderTest extends AbstractRaftActorBehaviorTest {
                             new MockRaftActorContext.MockPayload("D"));
 
                     // this should invoke a sendinstallsnapshot as followersLastIndex < snapshotIndex
-                    RaftState raftState = leader.handleMessage(
+                    RaftActorBehavior raftBehavior = leader.handleMessage(
                         senderActor, new Replicate(null, "state-id", entry));
 
-                    assertEquals(RaftState.Leader, raftState);
+                    assertTrue(raftBehavior instanceof Leader);
 
                     // we might receive some heartbeat messages, so wait till we SendInstallSnapshot
                     Boolean[] matches = new ReceiveWhile<Boolean>(Boolean.class, duration("2 seconds")) {
@@ -333,9 +332,9 @@ public class LeaderTest extends AbstractRaftActorBehaviorTest {
                         new ReplicatedLogImplEntry(newEntryIndex, currentTerm,
                             new MockRaftActorContext.MockPayload("D"));
 
-                    RaftState raftState = leader.handleMessage(senderActor, new SendInstallSnapshot());
+                    RaftActorBehavior raftBehavior = leader.handleMessage(senderActor, new SendInstallSnapshot());
 
-                    assertEquals(RaftState.Leader, raftState);
+                    assertTrue(raftBehavior instanceof Leader);
 
                     // check if installsnapshot gets called with the correct values.
                     final String out =
@@ -419,11 +418,11 @@ public class LeaderTest extends AbstractRaftActorBehaviorTest {
                     //clears leaders log
                     actorContext.getReplicatedLog().removeFrom(0);
 
-                    RaftState raftState = leader.handleMessage(senderActor,
+                    RaftActorBehavior raftBehavior = leader.handleMessage(senderActor,
                         new InstallSnapshotReply(currentTerm, followerActor.path().toString(),
                             leader.getFollowerToSnapshot().getChunkIndex(), true));
 
-                    assertEquals(RaftState.Leader, raftState);
+                    assertTrue(raftBehavior instanceof Leader);
 
                     assertEquals(leader.mapFollowerToSnapshot.size(), 0);
                     assertEquals(leader.followerToLog.size(), 1);
index aa136451a19511de6d032674086c9e45d34c0224..3053b057b263ac2dc155c3ac2bc234e87a0cbc30 100644 (file)
@@ -57,14 +57,14 @@ import com.google.common.util.concurrent.ListenableFuture;
 public class ListProcessingAndOrderingTest extends AbstractDataServiceTest {
 
     private static final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier DOM_UNORDERED_LIST_PATH = org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier
-            .builder(Lists.QNAME).node(UnorderedContainer.QNAME).node(UnorderedList.QNAME).build();
+            .builder().node(Lists.QNAME).node(UnorderedContainer.QNAME).node(UnorderedList.QNAME).build();
 
     private static final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier DOM_ORDERED_LIST_PATH = org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier
-            .builder(Lists.QNAME).node(OrderedContainer.QNAME).node(OrderedList.QNAME).build();
+            .builder().node(Lists.QNAME).node(OrderedContainer.QNAME).node(OrderedList.QNAME).build();
 
 
     private static final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier DOM_UNKEYED_LIST_PATH = org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier
-            .builder(Lists.QNAME).node(UnkeyedContainer.QNAME).node(UnkeyedList.QNAME).build();
+            .builder().node(Lists.QNAME).node(UnkeyedContainer.QNAME).node(UnkeyedList.QNAME).build();
 
     private static final InstanceIdentifier<UnorderedContainer> UNORDERED_CONTAINER_PATH = InstanceIdentifier.builder(Lists.class).child(UnorderedContainer.class).build();
     private static final InstanceIdentifier<OrderedContainer> ORDERED_CONTAINER_PATH = InstanceIdentifier.builder(Lists.class).child(OrderedContainer.class).build();
diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/common/actor/AbstractUntypedPersistentActorWithMetering.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/common/actor/AbstractUntypedPersistentActorWithMetering.java
new file mode 100644 (file)
index 0000000..365a5bd
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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.common.actor;
+
+/**
+ * Actor with its behaviour metered. Metering is enabled by configuration.
+ */
+public abstract class AbstractUntypedPersistentActorWithMetering extends AbstractUntypedPersistentActor {
+
+    public AbstractUntypedPersistentActorWithMetering() {
+        if (isMetricsCaptureEnabled())
+            getContext().become(new MeteringBehavior(this));
+    }
+
+    private boolean isMetricsCaptureEnabled(){
+        CommonConfig config = new CommonConfig(getContext().system().settings().config());
+        return config.isMetricCaptureEnabled();
+    }
+}
diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NodeToNormalizedNodeBuilder.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NodeToNormalizedNodeBuilder.java
deleted file mode 100644 (file)
index 03d632b..0000000
+++ /dev/null
@@ -1,856 +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.cluster.datastore.node;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import org.opendaylight.controller.cluster.datastore.node.utils.NodeIdentifierFactory;
-import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node;
-import org.opendaylight.yangtools.concepts.Identifiable;
-import org.opendaylight.yangtools.yang.common.QName;
-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.NodeWithValue;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
-import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
-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.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
-import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
-import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
-import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
-import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
-import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
-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.SchemaContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-import static com.google.common.base.Preconditions.checkArgument;
-
-/**
- * NormalizedNodeBuilder is a builder that walks through a tree like structure and constructs a
- * NormalizedNode from it.
- * <p/>
- * A large part of this code has been copied over from a similar class in sal-common-impl which was
- * originally supposed to convert a CompositeNode to NormalizedNode
- *
- * @param <T>
- */
-public abstract class NodeToNormalizedNodeBuilder<T extends PathArgument>
-    implements Identifiable<T> {
-
-    private final T identifier;
-
-    protected static final Logger logger = LoggerFactory
-        .getLogger(NodeToNormalizedNodeBuilder.class);
-
-    @Override
-    public T getIdentifier() {
-        return identifier;
-    }
-
-    ;
-
-    protected NodeToNormalizedNodeBuilder(final T identifier) {
-        super();
-        this.identifier = identifier;
-
-    }
-
-    /**
-     * @return Should return true if the node that this operation corresponds to is a mixin
-     */
-    public boolean isMixin() {
-        return false;
-    }
-
-
-    /**
-     * @return Should return true if the node that this operation corresponds to has a 'key'
-     * associated with it. This is typically true for a list-item or leaf-list entry in yang
-     */
-    public boolean isKeyedEntry() {
-        return false;
-    }
-
-    protected Set<QName> getQNameIdentifiers() {
-        return Collections.singleton(identifier.getNodeType());
-    }
-
-    public abstract NodeToNormalizedNodeBuilder<?> getChild(
-        final PathArgument child);
-
-    public abstract NodeToNormalizedNodeBuilder<?> getChild(QName child);
-
-    public abstract NormalizedNode<?, ?> normalize(QName nodeType, Node node);
-
-
-
-    private static abstract class SimpleTypeNormalization<T extends PathArgument>
-        extends NodeToNormalizedNodeBuilder<T> {
-
-        protected SimpleTypeNormalization(final T identifier) {
-            super(identifier);
-        }
-
-        @Override
-        public NormalizedNode<?, ?> normalize(final QName nodeType,
-            final Node node) {
-            checkArgument(node != null);
-            return normalizeImpl(nodeType, node);
-        }
-
-        protected abstract NormalizedNode<?, ?> normalizeImpl(QName nodeType,
-            Node node);
-
-        @Override
-        public NodeToNormalizedNodeBuilder<?> getChild(
-            final PathArgument child) {
-            return null;
-        }
-
-        @Override
-        public NodeToNormalizedNodeBuilder<?> getChild(final QName child) {
-            return null;
-        }
-
-        @Override
-        public NormalizedNode<?, ?> createDefault(
-            final PathArgument currentArg) {
-            // TODO Auto-generated method stub
-            return null;
-        }
-
-    }
-
-
-    private static final class LeafNormalization extends
-        SimpleTypeNormalization<NodeIdentifier> {
-
-        private final LeafSchemaNode schema;
-
-        protected LeafNormalization(final LeafSchemaNode schema, final NodeIdentifier identifier) {
-            super(identifier);
-            this.schema = schema;
-        }
-
-        @Override
-        protected NormalizedNode<?, ?> normalizeImpl(final QName nodeType,
-            final Node node) {
-            Object value = NodeValueCodec.toTypeSafeValue(this.schema, this.schema.getType(), node);
-            return ImmutableNodes.leafNode(nodeType, value);
-
-        }
-
-    }
-
-
-    private static final class LeafListEntryNormalization extends
-        SimpleTypeNormalization<NodeWithValue> {
-
-        private final LeafListSchemaNode schema;
-
-        public LeafListEntryNormalization(final LeafListSchemaNode potential) {
-            super(new NodeWithValue(potential.getQName(), null));
-            this.schema = potential;
-        }
-
-        @Override
-        protected NormalizedNode<?, ?> normalizeImpl(final QName nodeType,
-            final Node node) {
-            final Object data = node.getValue();
-            if (data == null) {
-                Preconditions.checkArgument(false,
-                    "No data available in leaf list entry for " + nodeType);
-            }
-
-            Object value = NodeValueCodec.toTypeSafeValue(this.schema, this.schema.getType(), node);
-
-            NodeWithValue nodeId = new NodeWithValue(nodeType, value);
-            return Builders.leafSetEntryBuilder().withNodeIdentifier(nodeId)
-                .withValue(value).build();
-        }
-
-
-        @Override
-        public boolean isKeyedEntry() {
-            return true;
-        }
-    }
-
-
-    private static abstract class NodeToNormalizationNodeOperation<T extends PathArgument>
-        extends NodeToNormalizedNodeBuilder<T> {
-
-        protected NodeToNormalizationNodeOperation(final T identifier) {
-            super(identifier);
-        }
-
-        @SuppressWarnings({"rawtypes", "unchecked"})
-        @Override
-        public final NormalizedNodeContainer<?, ?, ?> normalize(
-            final QName nodeType, final Node node) {
-            checkArgument(node != null);
-
-            if (!node.getType().equals(AugmentationNode.class.getSimpleName())
-                && !node.getType().equals(ContainerNode.class.getSimpleName())
-                && !node.getType().equals(MapNode.class.getSimpleName())) {
-                checkArgument(nodeType != null);
-            }
-
-            NormalizedNodeContainerBuilder builder = createBuilder(node);
-
-            Set<NodeToNormalizedNodeBuilder<?>> usedMixins = new HashSet<>();
-
-            logNode(node);
-
-            if (node.getChildCount() == 0 && (
-                node.getType().equals(LeafSetEntryNode.class.getSimpleName())
-                    || node.getType().equals(LeafNode.class.getSimpleName()))) {
-                PathArgument childPathArgument =
-                    NodeIdentifierFactory.getArgument(node.getPath());
-
-                final NormalizedNode child;
-                if (childPathArgument instanceof NodeWithValue) {
-                    final NodeWithValue nodeWithValue =
-                        new NodeWithValue(childPathArgument.getNodeType(),
-                            node.getValue());
-                    child =
-                        Builders.leafSetEntryBuilder()
-                            .withNodeIdentifier(nodeWithValue)
-                            .withValue(node.getValue()).build();
-                } else {
-                    child =
-                        ImmutableNodes.leafNode(childPathArgument.getNodeType(),
-                            node.getValue());
-                }
-                builder.addChild(child);
-            }
-
-            final List<Node> children = node.getChildList();
-            for (Node nodeChild : children) {
-
-                PathArgument childPathArgument =
-                    NodeIdentifierFactory.getArgument(nodeChild.getPath());
-
-                QName childNodeType = null;
-                NodeToNormalizedNodeBuilder childOp = null;
-
-                if (childPathArgument instanceof AugmentationIdentifier) {
-                    childOp = getChild(childPathArgument);
-                    checkArgument(childOp instanceof AugmentationNormalization, childPathArgument);
-                } else {
-                    childNodeType = childPathArgument.getNodeType();
-                    childOp = getChild(childNodeType);
-                }
-                // We skip unknown nodes if this node is mixin since
-                // it's nodes and parent nodes are interleaved
-                if (childOp == null && isMixin()) {
-                    continue;
-                } else if (childOp == null) {
-                    logger.error(
-                        "childOp is null and this operation is not a mixin : this = {}",
-                        this.toString());
-                }
-
-                checkArgument(childOp != null,
-                    "Node %s is not allowed inside %s",
-                    childNodeType, getIdentifier());
-
-                if (childOp.isMixin()) {
-                    if (usedMixins.contains(childOp)) {
-                        // We already run / processed that mixin, so to avoid
-                        // duplicate we are
-                        // skipping next nodes.
-                        continue;
-                    }
-                    // builder.addChild(childOp.normalize(nodeType, treeCacheNode));
-                    final NormalizedNode childNode =
-                        childOp.normalize(childNodeType, nodeChild);
-                    if (childNode != null)
-                        builder.addChild(childNode);
-                    usedMixins.add(childOp);
-                } else {
-                    final NormalizedNode childNode =
-                        childOp.normalize(childNodeType, nodeChild);
-                    if (childNode != null)
-                        builder.addChild(childNode);
-                }
-            }
-
-
-            try {
-                return (NormalizedNodeContainer<?, ?, ?>) builder.build();
-            } catch (Exception e) {
-                return null;
-            }
-
-        }
-
-        private void logNode(Node node) {
-            //let us find out the type of the node
-            logger.debug("We got a {} , with identifier {} with {} children",
-                node.getType(), node.getPath(),
-                node.getChildList());
-        }
-
-        @SuppressWarnings("rawtypes")
-        protected abstract NormalizedNodeContainerBuilder createBuilder(
-            final Node node);
-
-    }
-
-
-    private static abstract class DataContainerNormalizationOperation<T extends PathArgument>
-        extends NodeToNormalizationNodeOperation<T> {
-
-        private final DataNodeContainer schema;
-        private final Map<QName, NodeToNormalizedNodeBuilder<?>> byQName;
-        private final Map<PathArgument, NodeToNormalizedNodeBuilder<?>> byArg;
-
-        protected DataContainerNormalizationOperation(final T identifier,
-            final DataNodeContainer schema) {
-            super(identifier);
-            this.schema = schema;
-            this.byArg = new ConcurrentHashMap<>();
-            this.byQName = new ConcurrentHashMap<>();
-        }
-
-        @Override
-        public NodeToNormalizedNodeBuilder<?> getChild(
-            final PathArgument child) {
-            NodeToNormalizedNodeBuilder<?> potential = byArg.get(child);
-            if (potential != null) {
-                return potential;
-            }
-            potential = fromSchema(schema, child);
-            return register(potential);
-        }
-
-        @Override
-        public NodeToNormalizedNodeBuilder<?> getChild(final QName child) {
-            if (child == null) {
-                return null;
-            }
-
-            NodeToNormalizedNodeBuilder<?> potential = byQName.get(child);
-            if (potential != null) {
-                return potential;
-            }
-            potential = fromSchemaAndPathArgument(schema, child);
-            return register(potential);
-        }
-
-        private NodeToNormalizedNodeBuilder<?> register(
-            final NodeToNormalizedNodeBuilder<?> potential) {
-            if (potential != null) {
-                byArg.put(potential.getIdentifier(), potential);
-                for (QName qName : potential.getQNameIdentifiers()) {
-                    byQName.put(qName, potential);
-                }
-            }
-            return potential;
-        }
-
-    }
-
-
-    private static final class ListItemNormalization extends
-        DataContainerNormalizationOperation<NodeIdentifierWithPredicates> {
-
-        private final List<QName> keyDefinition;
-        private final ListSchemaNode schemaNode;
-
-        protected ListItemNormalization(
-            final NodeIdentifierWithPredicates identifier,
-            final ListSchemaNode schema) {
-            super(identifier, schema);
-            this.schemaNode = schema;
-            keyDefinition = schema.getKeyDefinition();
-        }
-
-        @Override
-        protected NormalizedNodeContainerBuilder createBuilder(
-            final Node node) {
-            NodeIdentifierWithPredicates nodeIdentifierWithPredicates =
-                (NodeIdentifierWithPredicates) NodeIdentifierFactory
-                    .createPathArgument(node
-                        .getPath(), schemaNode);
-            return Builders.mapEntryBuilder()
-                .withNodeIdentifier(
-                    nodeIdentifierWithPredicates
-            );
-        }
-
-        @Override
-        public NormalizedNode<?, ?> createDefault(
-            final PathArgument currentArg) {
-            DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode>
-                builder =
-                Builders.mapEntryBuilder().withNodeIdentifier(
-                    (NodeIdentifierWithPredicates) currentArg);
-            for (Entry<QName, Object> keyValue : ((NodeIdentifierWithPredicates) currentArg)
-                .getKeyValues().entrySet()) {
-                if (keyValue.getValue() == null) {
-                    throw new NullPointerException(
-                        "Null value found for path : "
-                            + currentArg);
-                }
-                builder.addChild(Builders.leafBuilder()
-                    //
-                    .withNodeIdentifier(new NodeIdentifier(keyValue.getKey()))
-                    .withValue(keyValue.getValue()).build());
-            }
-            return builder.build();
-        }
-
-
-        @Override
-        public boolean isKeyedEntry() {
-            return true;
-        }
-    }
-
-
-    private static final class ContainerNormalization extends
-        DataContainerNormalizationOperation<NodeIdentifier> {
-
-        protected ContainerNormalization(final ContainerSchemaNode schema) {
-            super(new NodeIdentifier(schema.getQName()), schema);
-        }
-
-        @Override
-        protected NormalizedNodeContainerBuilder createBuilder(
-            final Node node) {
-            return Builders.containerBuilder()
-                .withNodeIdentifier(getIdentifier());
-        }
-
-        @Override
-        public NormalizedNode<?, ?> createDefault(
-            final PathArgument currentArg) {
-            return Builders.containerBuilder()
-                .withNodeIdentifier((NodeIdentifier) currentArg).build();
-        }
-
-    }
-
-
-    private static abstract class MixinNormalizationOp<T extends PathArgument>
-        extends NodeToNormalizationNodeOperation<T> {
-
-        protected MixinNormalizationOp(final T identifier) {
-            super(identifier);
-        }
-
-        @Override
-        public final boolean isMixin() {
-            return true;
-        }
-
-    }
-
-
-    private static final class LeafListMixinNormalization extends
-        MixinNormalizationOp<NodeIdentifier> {
-
-        private final NodeToNormalizedNodeBuilder<?> innerOp;
-
-        public LeafListMixinNormalization(final LeafListSchemaNode potential) {
-            super(new NodeIdentifier(potential.getQName()));
-            innerOp = new LeafListEntryNormalization(potential);
-        }
-
-        @Override
-        protected NormalizedNodeContainerBuilder createBuilder(
-            final Node node) {
-            return Builders.leafSetBuilder()
-                .withNodeIdentifier(getIdentifier());
-        }
-
-        @Override
-        public NormalizedNode<?, ?> createDefault(
-            final PathArgument currentArg) {
-            return Builders.leafSetBuilder().withNodeIdentifier(getIdentifier())
-                .build();
-        }
-
-        @Override
-        public NodeToNormalizedNodeBuilder<?> getChild(
-            final PathArgument child) {
-            if (child instanceof NodeWithValue) {
-                return innerOp;
-            }
-            return null;
-        }
-
-        @Override
-        public NodeToNormalizedNodeBuilder<?> getChild(final QName child) {
-            if (getIdentifier().getNodeType().equals(child)) {
-                return innerOp;
-            }
-            return null;
-        }
-
-    }
-
-
-    private static final class AugmentationNormalization extends
-        MixinNormalizationOp<AugmentationIdentifier> {
-
-        private final Map<QName, NodeToNormalizedNodeBuilder<?>> byQName;
-        private final Map<PathArgument, NodeToNormalizedNodeBuilder<?>> byArg;
-
-        public AugmentationNormalization(final AugmentationSchema augmentation,
-            final DataNodeContainer schema) {
-            super(augmentationIdentifierFrom(augmentation));
-
-            ImmutableMap.Builder<QName, NodeToNormalizedNodeBuilder<?>>
-                byQNameBuilder =
-                ImmutableMap.builder();
-            ImmutableMap.Builder<PathArgument, NodeToNormalizedNodeBuilder<?>>
-                byArgBuilder =
-                ImmutableMap.builder();
-
-            for (DataSchemaNode augNode : augmentation.getChildNodes()) {
-                DataSchemaNode resolvedNode =
-                    schema.getDataChildByName(augNode.getQName());
-                NodeToNormalizedNodeBuilder<?> resolvedOp =
-                    fromDataSchemaNode(resolvedNode);
-                byArgBuilder.put(resolvedOp.getIdentifier(), resolvedOp);
-                for (QName resQName : resolvedOp.getQNameIdentifiers()) {
-                    byQNameBuilder.put(resQName, resolvedOp);
-                }
-            }
-            byQName = byQNameBuilder.build();
-            byArg = byArgBuilder.build();
-
-        }
-
-        @Override
-        public NodeToNormalizedNodeBuilder<?> getChild(
-            final PathArgument child) {
-            return byArg.get(child);
-        }
-
-        @Override
-        public NodeToNormalizedNodeBuilder<?> getChild(final QName child) {
-            return byQName.get(child);
-        }
-
-        @Override
-        protected Set<QName> getQNameIdentifiers() {
-            return getIdentifier().getPossibleChildNames();
-        }
-
-        @SuppressWarnings("rawtypes")
-        @Override
-        protected NormalizedNodeContainerBuilder createBuilder(
-            final Node node) {
-            return Builders.augmentationBuilder()
-                .withNodeIdentifier(getIdentifier());
-        }
-
-        @Override
-        public NormalizedNode<?, ?> createDefault(
-            final PathArgument currentArg) {
-            return Builders.augmentationBuilder()
-                .withNodeIdentifier(getIdentifier())
-                .build();
-        }
-
-    }
-
-
-    private static final class ListMixinNormalization extends
-        MixinNormalizationOp<NodeIdentifier> {
-
-        private final ListItemNormalization innerNode;
-
-        public ListMixinNormalization(final ListSchemaNode list) {
-            super(new NodeIdentifier(list.getQName()));
-            this.innerNode =
-                new ListItemNormalization(new NodeIdentifierWithPredicates(
-                    list.getQName(), Collections.<QName, Object>emptyMap()),
-                    list);
-        }
-
-        @SuppressWarnings("rawtypes")
-        @Override
-        protected NormalizedNodeContainerBuilder createBuilder(
-            final Node node) {
-            return Builders.mapBuilder().withNodeIdentifier(getIdentifier());
-        }
-
-        @Override
-        public NormalizedNode<?, ?> createDefault(
-            final PathArgument currentArg) {
-            return Builders.mapBuilder().withNodeIdentifier(getIdentifier())
-                .build();
-        }
-
-        @Override
-        public NodeToNormalizedNodeBuilder<?> getChild(
-            final PathArgument child) {
-            if (child.getNodeType().equals(getIdentifier().getNodeType())) {
-                return innerNode;
-            }
-            return null;
-        }
-
-        @Override
-        public NodeToNormalizedNodeBuilder<?> getChild(final QName child) {
-            if (getIdentifier().getNodeType().equals(child)) {
-                return innerNode;
-            }
-            return null;
-        }
-
-    }
-
-
-    private static class ChoiceNodeNormalization extends
-        MixinNormalizationOp<NodeIdentifier> {
-
-        private final ImmutableMap<QName, NodeToNormalizedNodeBuilder<?>>
-            byQName;
-        private final ImmutableMap<PathArgument, NodeToNormalizedNodeBuilder<?>>
-            byArg;
-
-        protected ChoiceNodeNormalization(
-            final org.opendaylight.yangtools.yang.model.api.ChoiceNode schema) {
-            super(new NodeIdentifier(schema.getQName()));
-            ImmutableMap.Builder<QName, NodeToNormalizedNodeBuilder<?>>
-                byQNameBuilder =
-                ImmutableMap.builder();
-            ImmutableMap.Builder<PathArgument, NodeToNormalizedNodeBuilder<?>>
-                byArgBuilder =
-                ImmutableMap.builder();
-
-            for (ChoiceCaseNode caze : schema.getCases()) {
-                for (DataSchemaNode cazeChild : caze.getChildNodes()) {
-                    NodeToNormalizedNodeBuilder<?> childOp =
-                        fromDataSchemaNode(cazeChild);
-                    byArgBuilder.put(childOp.getIdentifier(), childOp);
-                    for (QName qname : childOp.getQNameIdentifiers()) {
-                        byQNameBuilder.put(qname, childOp);
-                    }
-                }
-            }
-            byQName = byQNameBuilder.build();
-            byArg = byArgBuilder.build();
-        }
-
-        @Override
-        public NodeToNormalizedNodeBuilder<?> getChild(
-            final PathArgument child) {
-            return byArg.get(child);
-        }
-
-        @Override
-        public NodeToNormalizedNodeBuilder<?> getChild(final QName child) {
-            return byQName.get(child);
-        }
-
-        @Override
-        protected NormalizedNodeContainerBuilder createBuilder(
-            final Node node) {
-            return Builders.choiceBuilder().withNodeIdentifier(getIdentifier());
-        }
-
-        @Override
-        public NormalizedNode<?, ?> createDefault(
-            final PathArgument currentArg) {
-            return Builders.choiceBuilder().withNodeIdentifier(getIdentifier())
-                .build();
-        }
-    }
-
-    /**
-     * Find an appropriate NormalizedNodeBuilder using both the schema and the
-     * Path Argument
-     *
-     * @param schema
-     * @param child
-     * @return
-     */
-    public static NodeToNormalizedNodeBuilder<?> fromSchemaAndPathArgument(
-        final DataNodeContainer schema, final QName child) {
-        DataSchemaNode potential = schema.getDataChildByName(child);
-        if (potential == null) {
-            Iterable<org.opendaylight.yangtools.yang.model.api.ChoiceNode>
-                choices =
-                FluentIterable.from(schema.getChildNodes()).filter(
-                    org.opendaylight.yangtools.yang.model.api.ChoiceNode.class);
-            potential = findChoice(choices, child);
-        }
-        if (potential == null) {
-            if (logger.isTraceEnabled()) {
-                logger.trace("BAD CHILD = {}", child.toString());
-            }
-        }
-
-        checkArgument(potential != null,
-            "Supplied QName %s is not valid according to schema %s", child,
-            schema);
-
-        // If the schema in an instance of DataSchemaNode and the potential
-        // is augmenting something then there is a chance that this may be
-        // and augmentation node
-        if ((schema instanceof DataSchemaNode)
-            && potential.isAugmenting()) {
-
-            AugmentationNormalization augmentation =
-                fromAugmentation(schema, (AugmentationTarget) schema,
-                    potential);
-
-            // If an augmentation normalization (builder) is not found then
-            // we fall through to the regular processing
-            if(augmentation != null){
-                return augmentation;
-            }
-        }
-        return fromDataSchemaNode(potential);
-    }
-
-    /**
-     * Given a bunch of choice nodes and a the name of child find a choice node for that child which
-     * has a non-null value
-     *
-     * @param choices
-     * @param child
-     * @return
-     */
-    private static org.opendaylight.yangtools.yang.model.api.ChoiceNode findChoice(
-        final Iterable<org.opendaylight.yangtools.yang.model.api.ChoiceNode> choices,
-        final QName child) {
-        org.opendaylight.yangtools.yang.model.api.ChoiceNode foundChoice = null;
-        choiceLoop:
-        for (org.opendaylight.yangtools.yang.model.api.ChoiceNode choice : choices) {
-            for (ChoiceCaseNode caze : choice.getCases()) {
-                if (caze.getDataChildByName(child) != null) {
-                    foundChoice = choice;
-                    break choiceLoop;
-                }
-            }
-        }
-        return foundChoice;
-    }
-
-
-    /**
-     * Create an AugmentationIdentifier based on the AugmentationSchema
-     *
-     * @param augmentation
-     * @return
-     */
-    public static AugmentationIdentifier augmentationIdentifierFrom(
-        final AugmentationSchema augmentation) {
-        ImmutableSet.Builder<QName> potentialChildren = ImmutableSet.builder();
-        for (DataSchemaNode child : augmentation.getChildNodes()) {
-            potentialChildren.add(child.getQName());
-        }
-        return new AugmentationIdentifier(potentialChildren.build());
-    }
-
-    /**
-     * Create an AugmentationNormalization based on the schema of the DataContainer, the
-     * AugmentationTarget and the potential schema node
-     *
-     * @param schema
-     * @param augments
-     * @param potential
-     * @return
-     */
-    private static AugmentationNormalization fromAugmentation(
-        final DataNodeContainer schema, final AugmentationTarget augments,
-        final DataSchemaNode potential) {
-        AugmentationSchema augmentation = null;
-        for (AugmentationSchema aug : augments.getAvailableAugmentations()) {
-            DataSchemaNode child = aug.getDataChildByName(potential.getQName());
-            if (child != null) {
-                augmentation = aug;
-                break;
-            }
-
-        }
-        if (augmentation != null) {
-            return new AugmentationNormalization(augmentation, schema);
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * @param schema
-     * @param child
-     * @return
-     */
-    private static NodeToNormalizedNodeBuilder<?> fromSchema(
-        final DataNodeContainer schema, final PathArgument child) {
-        if (child instanceof AugmentationIdentifier) {
-            QName childQName = ((AugmentationIdentifier) child)
-                .getPossibleChildNames().iterator().next();
-
-            return fromSchemaAndPathArgument(schema, childQName);
-        }
-        return fromSchemaAndPathArgument(schema, child.getNodeType());
-    }
-
-    public static NodeToNormalizedNodeBuilder<?> fromDataSchemaNode(
-        final DataSchemaNode potential) {
-        if (potential instanceof ContainerSchemaNode) {
-            return new ContainerNormalization((ContainerSchemaNode) potential);
-        } else if (potential instanceof ListSchemaNode) {
-            return new ListMixinNormalization((ListSchemaNode) potential);
-        } else if (potential instanceof LeafSchemaNode) {
-            return new LeafNormalization((LeafSchemaNode) potential,
-                new NodeIdentifier(potential.getQName()));
-        } else if (potential instanceof org.opendaylight.yangtools.yang.model.api.ChoiceNode) {
-            return new ChoiceNodeNormalization(
-                (org.opendaylight.yangtools.yang.model.api.ChoiceNode) potential);
-        } else if (potential instanceof LeafListSchemaNode) {
-            return new LeafListMixinNormalization(
-                (LeafListSchemaNode) potential);
-        }
-        return null;
-    }
-
-    public static NodeToNormalizedNodeBuilder<?> from(final SchemaContext ctx) {
-        return new ContainerNormalization(ctx);
-    }
-
-    public abstract NormalizedNode<?, ?> createDefault(PathArgument currentArg);
-
-}
diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NodeValueCodec.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NodeValueCodec.java
deleted file mode 100644 (file)
index b6dbefb..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- *
- *  Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
- *
- *  This program and the accompanying materials are made available under the
- *  terms of the Eclipse Public License v1.0 which accompanies this distribution,
- *  and is available at http://www.eclipse.org/legal/epl-v10.html
- *
- */
-
-package org.opendaylight.controller.cluster.datastore.node;
-
-import org.opendaylight.controller.cluster.datastore.node.utils.QNameFactory;
-import org.opendaylight.controller.cluster.datastore.util.InstanceIdentifierUtils;
-import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages;
-import org.opendaylight.yangtools.yang.data.api.codec.BitsCodec;
-import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
-import org.opendaylight.yangtools.yang.model.util.IdentityrefType;
-import org.opendaylight.yangtools.yang.model.util.InstanceIdentifierType;
-import org.opendaylight.yangtools.yang.model.util.Leafref;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class NodeValueCodec {
-    protected static final Logger logger = LoggerFactory
-        .getLogger(NodeValueCodec.class);
-
-    public static Object toTypeSafeValue(DataSchemaNode schema, TypeDefinition type, NormalizedNodeMessages.Node node){
-
-        String value = node.getValue();
-
-        if(schema != null && value != null){
-            TypeDefinition<?> baseType = type;
-
-            while (baseType.getBaseType() != null) {
-                baseType = baseType.getBaseType();
-            }
-
-            TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> codec =
-                TypeDefinitionAwareCodec.from(type);
-
-            if(codec instanceof BitsCodec){
-                if(value.contains("[]")){
-                    value = "";
-                } else {
-                    value = value.replace("[", "");
-                    value = value.replace("]", "");
-                    value = value.replace(",", " ");
-                }
-            }
-
-            if (codec != null) {
-                return codec.deserialize(value);
-            } else if(baseType instanceof Leafref) {
-                return value;
-            } else if(baseType instanceof IdentityrefType) {
-                return QNameFactory.create(value);
-            } else if(baseType instanceof InstanceIdentifierType) {
-                return InstanceIdentifierUtils.fromSerializable(node.getInstanceIdentifierValue());
-            } else {
-                logger.error("Could not figure out how to transform value " + value +  " for schemaType " + type);
-            }
-        }
-
-        return value;
-    }
-}
diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToProtocolBufferNode.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToProtocolBufferNode.java
deleted file mode 100644 (file)
index 68d3c59..0000000
+++ /dev/null
@@ -1,264 +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.cluster.datastore.node;
-
-import com.google.common.base.Preconditions;
-import org.opendaylight.controller.cluster.datastore.util.InstanceIdentifierUtils;
-import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages;
-import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-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.LeafSetEntryNode;
-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.NormalizedNodeContainer;
-import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
-
-import java.util.Map;
-
-/**
- * NormalizedNodeToProtocolBufferNode walks the NormalizedNode tree converting it to the
- * NormalizedMessage.Node
- * <p/>
- * {@link org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode } is a tree like structure that provides a generic structure for a yang data
- * model
- */
-public class NormalizedNodeToProtocolBufferNode {
-
-
-    private final Node.Builder builderRoot;
-    private NormalizedNodeMessages.Container container;
-
-    public NormalizedNodeToProtocolBufferNode() {
-
-        builderRoot = Node.newBuilder();
-    }
-
-    public void encode(String parentPath, NormalizedNode<?, ?> normalizedNode) {
-        if (parentPath == null) {
-            parentPath = "";
-        }
-
-        NormalizedNodeMessages.Container.Builder containerBuilder =
-            NormalizedNodeMessages.Container.newBuilder();
-
-        if (normalizedNode != null) {
-
-            navigateNormalizedNode(0, parentPath, normalizedNode, builderRoot);
-            // here we need to put back the Node Tree in Container
-
-            container =
-                containerBuilder.setParentPath(parentPath).setNormalizedNode(
-                    builderRoot.build()).build();
-        } else {
-            //this can happen when an attempt was made to read from datastore and normalized node was null.
-            container = containerBuilder.setParentPath(parentPath).build();
-
-        }
-
-    }
-
-
-    private void navigateDataContainerNode(int level, final String parentPath,
-        final DataContainerNode<?> dataContainerNode,
-        Node.Builder builderParent) {
-
-        String newParentPath =
-            parentPath + "/" + dataContainerNode.getIdentifier().toString();
-        String type = getDataContainerType(dataContainerNode).getSimpleName();
-        builderParent.setPath(dataContainerNode.getIdentifier().toString())
-            .setType(type);
-
-        final Iterable<DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?>>
-            value =
-            dataContainerNode.getValue();
-        for (NormalizedNode<?, ?> node : value) {
-            Node.Builder builderChild = Node.newBuilder();
-            if (node instanceof MixinNode
-                && node instanceof NormalizedNodeContainer) {
-
-                navigateNormalizedNodeContainerMixin(level, newParentPath,
-                    (NormalizedNodeContainer<?, ?, ?>) node, builderChild);
-            } else {
-                navigateNormalizedNode(level, newParentPath, node,
-                    builderChild);
-            }
-            builderParent.addChild(builderChild);
-        }
-    }
-
-    private Class getDataContainerType(
-        NormalizedNodeContainer<?, ?, ?> dataContainerNode) {
-        if (dataContainerNode instanceof ChoiceNode) {
-            return ChoiceNode.class;
-        } else if (dataContainerNode instanceof AugmentationNode) {
-            return AugmentationNode.class;
-        } else if (dataContainerNode instanceof ContainerNode) {
-            return ContainerNode.class;
-        } else if (dataContainerNode instanceof MapEntryNode) {
-            return MapEntryNode.class;
-        } else if (dataContainerNode instanceof UnkeyedListEntryNode) {
-            return UnkeyedListEntryNode.class;
-        } else if (dataContainerNode instanceof MapNode) {
-            return MapNode.class;
-        } else if (dataContainerNode instanceof LeafSetNode) {
-            return LeafSetNode.class;
-        }
-        throw new IllegalArgumentException(
-            "could not find the data container node type "
-                + dataContainerNode.toString()
-        );
-    }
-
-    private void navigateNormalizedNodeContainerMixin(int level,
-        final String parentPath,
-        NormalizedNodeContainer<?, ?, ?> node, Node.Builder builderParent) {
-        String newParentPath =
-            parentPath + "/" + node.getIdentifier().toString();
-
-        builderParent.setPath(node.getIdentifier().toString()).setType(
-            this.getDataContainerType(node).getSimpleName());
-        final Iterable<? extends NormalizedNode<?, ?>> value = node.getValue();
-        for (NormalizedNode normalizedNode : value) {
-            // child node builder
-            Node.Builder builderChild = Node.newBuilder();
-            if (normalizedNode instanceof MixinNode
-                && normalizedNode instanceof NormalizedNodeContainer) {
-                navigateNormalizedNodeContainerMixin(level + 1, newParentPath,
-                    (NormalizedNodeContainer) normalizedNode, builderChild);
-            } else {
-                navigateNormalizedNode(level, newParentPath, normalizedNode,
-                    builderChild);
-            }
-            builderParent.addChild(builderChild);
-
-        }
-
-
-
-    }
-
-
-    private void navigateNormalizedNode(int level,
-        String parentPath, NormalizedNode<?, ?> normalizedNode,
-        Node.Builder builderParent) {
-
-        if (normalizedNode instanceof DataContainerNode) {
-
-            final DataContainerNode<?> dataContainerNode =
-                (DataContainerNode) normalizedNode;
-
-            navigateDataContainerNode(level + 1, parentPath, dataContainerNode,
-                builderParent);
-        } else if (normalizedNode instanceof MixinNode
-            && normalizedNode instanceof NormalizedNodeContainer) {
-
-            navigateNormalizedNodeContainerMixin(level, parentPath,
-                (NormalizedNodeContainer<?, ?, ?>) normalizedNode,
-                builderParent);
-        } else {
-            if (normalizedNode instanceof LeafNode) {
-                buildLeafNode(parentPath, normalizedNode, builderParent);
-            } else if (normalizedNode instanceof LeafSetEntryNode) {
-                buildLeafSetEntryNode(parentPath, normalizedNode,
-                    builderParent);
-            }
-
-        }
-
-    }
-
-    private void buildLeafSetEntryNode(String parentPath,
-        NormalizedNode<?, ?> normalizedNode,
-        Node.Builder builderParent) {
-        String path =
-            parentPath + "/" + normalizedNode.getIdentifier().toString();
-        LeafSetEntryNode leafSetEntryNode = (LeafSetEntryNode) normalizedNode;
-        Map<QName, String> attributes = leafSetEntryNode.getAttributes();
-        if (!attributes.isEmpty()) {
-            NormalizedNodeMessages.Attribute.Builder builder = null;
-            for (Map.Entry<QName, String> attribute : attributes.entrySet()) {
-                builder = NormalizedNodeMessages.Attribute.newBuilder();
-
-                builder
-                    .setName(attribute.getKey().toString())
-                    .setValue(normalizedNode.getValue().toString());
-
-                builderParent.addAttributes(builder.build());
-            }
-        }
-        buildNodeValue(normalizedNode, builderParent);
-    }
-
-    private void buildLeafNode(String parentPath,
-        NormalizedNode<?, ?> normalizedNode,
-        Node.Builder builderParent) {
-        Preconditions.checkNotNull(parentPath);
-        Preconditions.checkNotNull(normalizedNode);
-        String path =
-            parentPath + "/" + normalizedNode.getIdentifier().toString();
-        LeafNode leafNode = (LeafNode) normalizedNode;
-        Map<QName, String> attributes = leafNode.getAttributes();
-        if (!attributes.isEmpty()) {
-            NormalizedNodeMessages.Attribute.Builder builder = null;
-            for (Map.Entry<QName, String> attribute : attributes.entrySet()) {
-                builder = NormalizedNodeMessages.Attribute.newBuilder();
-                builder
-                    .setName(attribute.getKey().toString())
-                    .setValue(attribute.getValue().toString());
-
-                builderParent.addAttributes(builder.build());
-            }
-        }
-
-        Object value = normalizedNode.getValue();
-        if (value == null) {
-            builderParent
-                .setPath(normalizedNode.getIdentifier().toString())
-                .setType(LeafNode.class.getSimpleName())
-                .setValueType(String.class.getSimpleName())
-                .setValue("");
-        } else {
-            buildNodeValue(normalizedNode, builderParent);
-        }
-    }
-
-    private void buildNodeValue(NormalizedNode<?, ?> normalizedNode,
-        Node.Builder builderParent) {
-
-        Object value = normalizedNode.getValue();
-
-        builderParent
-            .setPath(normalizedNode.getIdentifier().toString())
-            .setType(LeafNode.class.getSimpleName())
-            .setValueType((value.getClass().getSimpleName()))
-            .setValue(value.toString());
-
-        if(value.getClass().equals(YangInstanceIdentifier.class)){
-            builderParent.setInstanceIdentifierValue(
-                InstanceIdentifierUtils
-                    .toSerializable((YangInstanceIdentifier) value));
-        }
-    }
-
-    public NormalizedNodeMessages.Container getContainer() {
-        return container;
-    }
-}
index e2c4c358935c184c9244b969533fcf86175e55e8..7f7cdc650ee70c5038a7159fb4d7ea4a81a80679 100644 (file)
@@ -46,7 +46,7 @@ public class AugmentationIdentifierGenerator {
                     .create(name.trim()));
         }
 
-        return new YangInstanceIdentifier.AugmentationIdentifier(null, childNames);
+        return new YangInstanceIdentifier.AugmentationIdentifier(childNames);
     }
 
 }
index ea3986f4a0a35fd840a92d341a18f5ccb614a256..da61e6de7327c9b3adabf30bf9d621561dd7c998 100644 (file)
@@ -32,20 +32,6 @@ public class NodeIdentifierFactory {
         return value;
     }
 
-    public static YangInstanceIdentifier.PathArgument getArgument(String id, DataSchemaNode schemaNode){
-        YangInstanceIdentifier.PathArgument value = cache.get(id);
-        if(value == null){
-            synchronized (cache){
-                value = cache.get(id);
-                if(value == null) {
-                    value = createPathArgument(id, schemaNode);
-                    cache.put(id, value);
-                }
-            }
-        }
-        return value;
-    }
-
     public static YangInstanceIdentifier.PathArgument createPathArgument(String id, DataSchemaNode schemaNode){
         final NodeIdentifierWithPredicatesGenerator
             nodeIdentifierWithPredicatesGenerator = new NodeIdentifierWithPredicatesGenerator(id, schemaNode);
diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/util/EncoderDecoderUtil.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/util/EncoderDecoderUtil.java
deleted file mode 100644 (file)
index 90f5cf3..0000000
+++ /dev/null
@@ -1,333 +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.cluster.datastore.util;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
-import org.opendaylight.controller.protobuff.messages.common.SimpleNormalizedNodeMessage;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
-import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
-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.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils;
-import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils;
-import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory;
-import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.serializer.DomFromNormalizedNodeSerializerFactory;
-import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
-import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
-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.Module;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.TransformerFactoryConfigurationError;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
-import java.io.ByteArrayInputStream;
-import java.io.StringWriter;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-
-/*
- *
- * <code>EncoderDecoderUtil</code> helps in wrapping the NormalizedNode into a SimpleNormalizedNode
- * protobuf message containing the XML representation of the NormalizeNode
- *
- * @author: syedbahm
- */
-public class EncoderDecoderUtil {
-    static DocumentBuilderFactory factory;
-
-    private static DomFromNormalizedNodeSerializerFactory serializerFactory =
-        DomFromNormalizedNodeSerializerFactory
-            .getInstance(XmlDocumentUtils.getDocument(),
-                DomUtils.defaultValueCodecProvider());
-
-    private static DomToNormalizedNodeParserFactory parserFactory =
-        DomToNormalizedNodeParserFactory
-            .getInstance(DomUtils.defaultValueCodecProvider());
-
-    static {
-        factory = DocumentBuilderFactory.newInstance();
-        factory.setNamespaceAware(true);
-        factory.setCoalescing(true);
-        factory.setIgnoringElementContentWhitespace(true);
-        factory.setIgnoringComments(true);
-    }
-
-    private static DataSchemaNode findChildNode(Collection<DataSchemaNode> children,
-        String name) {
-        List<DataNodeContainer> containers = Lists.newArrayList();
-
-        for (DataSchemaNode dataSchemaNode : children) {
-            if (dataSchemaNode.getQName().getLocalName().equals(name))
-                return dataSchemaNode;
-            if (dataSchemaNode instanceof DataNodeContainer) {
-                containers.add((DataNodeContainer) dataSchemaNode);
-            } else if (dataSchemaNode instanceof ChoiceNode) {
-                containers.addAll(((ChoiceNode) dataSchemaNode).getCases());
-            }
-        }
-
-        for (DataNodeContainer container : containers) {
-            DataSchemaNode retVal =
-                findChildNode(container.getChildNodes(), name);
-            if (retVal != null) {
-                return retVal;
-            }
-        }
-
-        return null;
-    }
-
-    private static DataSchemaNode getSchemaNode(SchemaContext context,
-        QName qname) {
-
-        for (Module module : context
-            .findModuleByNamespace(qname.getNamespace())) {
-            // we will take the first child as the start of the
-            if (module.getChildNodes() != null || !module.getChildNodes()
-                .isEmpty()) {
-
-                DataSchemaNode found =
-                    findChildNode(module.getChildNodes(), qname.getLocalName());
-                return found;
-            }
-        }
-        return null;
-    }
-
-    private static String toString(Element xml) {
-        try {
-            Transformer transformer =
-                TransformerFactory.newInstance().newTransformer();
-            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
-
-            StreamResult result = new StreamResult(new StringWriter());
-            DOMSource source = new DOMSource(xml);
-            transformer.transform(source, result);
-
-            return result.getWriter().toString();
-        } catch (IllegalArgumentException | TransformerFactoryConfigurationError
-            | TransformerException e) {
-            throw new RuntimeException("Unable to serialize xml element " + xml,
-                e);
-        }
-    }
-
-  private static String toString(Iterable<Element> xmlIterable) {
-    try {
-      Transformer transformer =
-          TransformerFactory.newInstance().newTransformer();
-      transformer.setOutputProperty(OutputKeys.INDENT, "yes");
-
-      StreamResult result = new StreamResult(new StringWriter());
-      Iterator iterator = xmlIterable.iterator();
-      DOMSource source;
-      if(iterator.hasNext()) {
-        source = new DOMSource((org.w3c.dom.Node) iterator.next());
-        transformer.transform(source, result);
-        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
-      }
-
-      while(iterator.hasNext()) {
-        source = new DOMSource((org.w3c.dom.Node) iterator.next());
-        transformer.transform(source, result);
-      }
-      System.out.println(result.getWriter().toString());
-      return result.getWriter().toString();
-    } catch (IllegalArgumentException | TransformerFactoryConfigurationError
-        | TransformerException e) {
-      throw new RuntimeException("Unable to serialize xml element(s) " + xmlIterable.toString(),
-          e);
-    }
-  }
-
-    private static Iterable<Element> serialize(DataSchemaNode schemaNode, NormalizedNode normalizedNode){
-        if(schemaNode instanceof ContainerSchemaNode){      //1
-            return serializerFactory
-                .getContainerNodeSerializer()
-                .serialize((ContainerSchemaNode) schemaNode,
-                    (ContainerNode) normalizedNode);
-        } else if(schemaNode instanceof ChoiceNode){        //2
-            return serializerFactory
-                .getChoiceNodeSerializer()
-                .serialize((ChoiceNode) schemaNode,
-                    (org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode) normalizedNode);
-        } else if(schemaNode instanceof LeafSchemaNode){    //3
-            return serializerFactory
-                .getLeafNodeSerializer()
-                .serialize((LeafSchemaNode) schemaNode, (LeafNode) normalizedNode);
-        } else if(schemaNode instanceof ListSchemaNode){    //4
-            return serializerFactory
-                .getMapNodeSerializer()
-                .serialize((ListSchemaNode) schemaNode, (MapNode) normalizedNode);
-        } else if(schemaNode instanceof LeafListSchemaNode){    //5
-            return serializerFactory
-                .getLeafSetNodeSerializer()
-                .serialize((LeafListSchemaNode) schemaNode, (LeafSetNode) normalizedNode);
-        } else if(schemaNode instanceof AugmentationSchema){//6
-            return serializerFactory
-                .getAugmentationNodeSerializer()
-                .serialize((AugmentationSchema) schemaNode, (AugmentationNode) normalizedNode);
-        } else if(schemaNode instanceof ListSchemaNode && normalizedNode instanceof LeafSetEntryNode){    //7
-            return serializerFactory
-                .getLeafSetEntryNodeSerializer()
-                .serialize((LeafListSchemaNode) schemaNode, (LeafSetEntryNode) normalizedNode);
-        } else if(schemaNode instanceof ListSchemaNode){    //8
-            return serializerFactory
-                .getMapEntryNodeSerializer()
-                .serialize((ListSchemaNode) schemaNode, (MapEntryNode) normalizedNode);
-        }
-
-
-
-        throw new UnsupportedOperationException(schemaNode.getClass().toString());
-    }
-
-    private static NormalizedNode parse(Document doc, DataSchemaNode schemaNode){
-        if(schemaNode instanceof ContainerSchemaNode){
-            return parserFactory
-                .getContainerNodeParser()
-                .parse(Collections.singletonList(doc.getDocumentElement()),
-                    (ContainerSchemaNode) schemaNode);
-
-        } else if(schemaNode instanceof ChoiceNode){
-            return parserFactory
-                .getChoiceNodeParser()
-                .parse(Collections.singletonList(doc.getDocumentElement()),
-                    (ChoiceNode) schemaNode);
-        } else if(schemaNode instanceof LeafNode){
-            return parserFactory
-                .getLeafNodeParser()
-                .parse(Collections.singletonList(doc.getDocumentElement()),
-                    (LeafSchemaNode) schemaNode);
-        } else if(schemaNode instanceof ListSchemaNode){
-            return parserFactory
-                .getMapNodeParser()
-                .parse(Collections.singletonList(doc.getDocumentElement()),
-                    (ListSchemaNode) schemaNode);
-        } else if(schemaNode instanceof LeafListSchemaNode){
-            return parserFactory
-                .getLeafSetNodeParser()
-                .parse(Collections.singletonList(doc.getDocumentElement()),
-                    (LeafListSchemaNode) schemaNode);
-        } else if(schemaNode instanceof AugmentationSchema){
-            return parserFactory
-                .getAugmentationNodeParser()
-                .parse(Collections.singletonList(doc.getDocumentElement()),
-                    (AugmentationSchema) schemaNode);
-        } else if(schemaNode instanceof ListSchemaNode){
-            return parserFactory
-                .getMapEntryNodeParser()
-                .parse(Collections.singletonList(doc.getDocumentElement()),
-                    (ListSchemaNode) schemaNode);
-
-        }
-
-        throw new UnsupportedOperationException(schemaNode.getClass().toString());
-    }
-
-
-    /**
-     * Helps in generation of NormalizedNodeXml message for the supplied NormalizedNode
-     *
-     * @param sc             --SchemaContext
-     * @param normalizedNode -- Normalized Node to be encoded
-     * @return SimpleNormalizedNodeMessage.NormalizedNodeXml
-     */
-    public static SimpleNormalizedNodeMessage.NormalizedNodeXml encode(
-        SchemaContext sc, NormalizedNode<?, ?> normalizedNode) {
-
-        Preconditions.checkArgument(sc != null, "Schema context found null");
-
-        Preconditions.checkArgument(normalizedNode != null,
-            "normalized node found null");
-
-        DataSchemaNode schemaNode = getSchemaNode(sc,
-            normalizedNode.getIdentifier()
-                .getNodeType()
-        );
-
-        Preconditions.checkState(schemaNode != null,
-            "Couldn't find schema node for " + normalizedNode.getIdentifier());
-
-        Iterable<Element> els = serialize(schemaNode, normalizedNode);
-
-        String xmlString = toString(els.iterator().next());
-        SimpleNormalizedNodeMessage.NormalizedNodeXml.Builder builder =
-            SimpleNormalizedNodeMessage.NormalizedNodeXml.newBuilder();
-        builder.setXmlString(xmlString);
-        builder
-            .setNodeIdentifier(normalizedNode.getIdentifier()
-                .getNodeType().toString());
-        return builder.build();
-
-    }
-
-    /**
-     * Utilizes the SimpleNormalizedNodeMessage.NormalizedNodeXml to convert into NormalizedNode
-     *
-     * @param sc                -- schema context
-     * @param normalizedNodeXml -- containing the normalized Node XML
-     * @return NormalizedNode return
-     * @throws Exception
-     */
-
-    public static NormalizedNode decode(SchemaContext sc,
-        SimpleNormalizedNodeMessage.NormalizedNodeXml normalizedNodeXml)
-        throws Exception {
-
-        Preconditions
-            .checkArgument(sc != null, "schema context seems to be null");
-
-        Preconditions.checkArgument(normalizedNodeXml != null,
-            "SimpleNormalizedNodeMessage.NormalizedNodeXml found to be null");
-        QName qname = QName.create(normalizedNodeXml.getNodeIdentifier());
-
-        // here we will try to get back the NormalizedNode
-        DataSchemaNode schemaNode = getSchemaNode(sc, qname);
-
-        // now we need to read the XML
-        Document doc =
-            factory.newDocumentBuilder().parse(
-                new ByteArrayInputStream(
-                    normalizedNodeXml.getXmlString().getBytes(
-                        "utf-8"))
-            );
-
-        doc.getDocumentElement().normalize();
-
-
-        return parse(doc, schemaNode);
-    }
-
-
-
-}
index 22a93c0e108a13f80b3fc30b33f7416e2516fe52..e43b44582d77b5526234e301535d368a2f83fede 100644 (file)
@@ -10,6 +10,21 @@ public final class ThreePhaseCommitCohortMessages {
   }
   public interface CanCommitTransactionOrBuilder
       extends com.google.protobuf.MessageOrBuilder {
+
+    // required string transactionId = 1;
+    /**
+     * <code>required string transactionId = 1;</code>
+     */
+    boolean hasTransactionId();
+    /**
+     * <code>required string transactionId = 1;</code>
+     */
+    java.lang.String getTransactionId();
+    /**
+     * <code>required string transactionId = 1;</code>
+     */
+    com.google.protobuf.ByteString
+        getTransactionIdBytes();
   }
   /**
    * Protobuf type {@code org.opendaylight.controller.mdsal.CanCommitTransaction}
@@ -44,6 +59,7 @@ public final class ThreePhaseCommitCohortMessages {
         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 {
@@ -61,6 +77,11 @@ public final class ThreePhaseCommitCohortMessages {
               }
               break;
             }
+            case 10: {
+              bitField0_ |= 0x00000001;
+              transactionId_ = input.readBytes();
+              break;
+            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -100,13 +121,62 @@ public final class ThreePhaseCommitCohortMessages {
       return PARSER;
     }
 
+    private int bitField0_;
+    // required string transactionId = 1;
+    public static final int TRANSACTIONID_FIELD_NUMBER = 1;
+    private java.lang.Object transactionId_;
+    /**
+     * <code>required string transactionId = 1;</code>
+     */
+    public boolean hasTransactionId() {
+      return ((bitField0_ & 0x00000001) == 0x00000001);
+    }
+    /**
+     * <code>required string transactionId = 1;</code>
+     */
+    public java.lang.String getTransactionId() {
+      java.lang.Object ref = transactionId_;
+      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()) {
+          transactionId_ = s;
+        }
+        return s;
+      }
+    }
+    /**
+     * <code>required string transactionId = 1;</code>
+     */
+    public com.google.protobuf.ByteString
+        getTransactionIdBytes() {
+      java.lang.Object ref = transactionId_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b =
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        transactionId_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
     private void initFields() {
+      transactionId_ = "";
     }
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
       byte isInitialized = memoizedIsInitialized;
       if (isInitialized != -1) return isInitialized == 1;
 
+      if (!hasTransactionId()) {
+        memoizedIsInitialized = 0;
+        return false;
+      }
       memoizedIsInitialized = 1;
       return true;
     }
@@ -114,6 +184,9 @@ public final class ThreePhaseCommitCohortMessages {
     public void writeTo(com.google.protobuf.CodedOutputStream output)
                         throws java.io.IOException {
       getSerializedSize();
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        output.writeBytes(1, getTransactionIdBytes());
+      }
       getUnknownFields().writeTo(output);
     }
 
@@ -123,6 +196,10 @@ public final class ThreePhaseCommitCohortMessages {
       if (size != -1) return size;
 
       size = 0;
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(1, getTransactionIdBytes());
+      }
       size += getUnknownFields().getSerializedSize();
       memoizedSerializedSize = size;
       return size;
@@ -239,6 +316,8 @@ public final class ThreePhaseCommitCohortMessages {
 
       public Builder clear() {
         super.clear();
+        transactionId_ = "";
+        bitField0_ = (bitField0_ & ~0x00000001);
         return this;
       }
 
@@ -265,6 +344,13 @@ public final class ThreePhaseCommitCohortMessages {
 
       public org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages.CanCommitTransaction buildPartial() {
         org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages.CanCommitTransaction result = new org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages.CanCommitTransaction(this);
+        int from_bitField0_ = bitField0_;
+        int to_bitField0_ = 0;
+        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
+          to_bitField0_ |= 0x00000001;
+        }
+        result.transactionId_ = transactionId_;
+        result.bitField0_ = to_bitField0_;
         onBuilt();
         return result;
       }
@@ -280,11 +366,20 @@ public final class ThreePhaseCommitCohortMessages {
 
       public Builder mergeFrom(org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages.CanCommitTransaction other) {
         if (other == org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages.CanCommitTransaction.getDefaultInstance()) return this;
+        if (other.hasTransactionId()) {
+          bitField0_ |= 0x00000001;
+          transactionId_ = other.transactionId_;
+          onChanged();
+        }
         this.mergeUnknownFields(other.getUnknownFields());
         return this;
       }
 
       public final boolean isInitialized() {
+        if (!hasTransactionId()) {
+
+          return false;
+        }
         return true;
       }
 
@@ -305,6 +400,81 @@ public final class ThreePhaseCommitCohortMessages {
         }
         return this;
       }
+      private int bitField0_;
+
+      // required string transactionId = 1;
+      private java.lang.Object transactionId_ = "";
+      /**
+       * <code>required string transactionId = 1;</code>
+       */
+      public boolean hasTransactionId() {
+        return ((bitField0_ & 0x00000001) == 0x00000001);
+      }
+      /**
+       * <code>required string transactionId = 1;</code>
+       */
+      public java.lang.String getTransactionId() {
+        java.lang.Object ref = transactionId_;
+        if (!(ref instanceof java.lang.String)) {
+          java.lang.String s = ((com.google.protobuf.ByteString) ref)
+              .toStringUtf8();
+          transactionId_ = s;
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>required string transactionId = 1;</code>
+       */
+      public com.google.protobuf.ByteString
+          getTransactionIdBytes() {
+        java.lang.Object ref = transactionId_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b =
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          transactionId_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>required string transactionId = 1;</code>
+       */
+      public Builder setTransactionId(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000001;
+        transactionId_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>required string transactionId = 1;</code>
+       */
+      public Builder clearTransactionId() {
+        bitField0_ = (bitField0_ & ~0x00000001);
+        transactionId_ = getDefaultInstance().getTransactionId();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>required string transactionId = 1;</code>
+       */
+      public Builder setTransactionIdBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000001;
+        transactionId_ = value;
+        onChanged();
+        return this;
+      }
 
       // @@protoc_insertion_point(builder_scope:org.opendaylight.controller.mdsal.CanCommitTransaction)
     }
@@ -723,6 +893,21 @@ public final class ThreePhaseCommitCohortMessages {
 
   public interface AbortTransactionOrBuilder
       extends com.google.protobuf.MessageOrBuilder {
+
+    // required string transactionId = 1;
+    /**
+     * <code>required string transactionId = 1;</code>
+     */
+    boolean hasTransactionId();
+    /**
+     * <code>required string transactionId = 1;</code>
+     */
+    java.lang.String getTransactionId();
+    /**
+     * <code>required string transactionId = 1;</code>
+     */
+    com.google.protobuf.ByteString
+        getTransactionIdBytes();
   }
   /**
    * Protobuf type {@code org.opendaylight.controller.mdsal.AbortTransaction}
@@ -757,6 +942,7 @@ public final class ThreePhaseCommitCohortMessages {
         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 {
@@ -774,6 +960,11 @@ public final class ThreePhaseCommitCohortMessages {
               }
               break;
             }
+            case 10: {
+              bitField0_ |= 0x00000001;
+              transactionId_ = input.readBytes();
+              break;
+            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -813,13 +1004,62 @@ public final class ThreePhaseCommitCohortMessages {
       return PARSER;
     }
 
+    private int bitField0_;
+    // required string transactionId = 1;
+    public static final int TRANSACTIONID_FIELD_NUMBER = 1;
+    private java.lang.Object transactionId_;
+    /**
+     * <code>required string transactionId = 1;</code>
+     */
+    public boolean hasTransactionId() {
+      return ((bitField0_ & 0x00000001) == 0x00000001);
+    }
+    /**
+     * <code>required string transactionId = 1;</code>
+     */
+    public java.lang.String getTransactionId() {
+      java.lang.Object ref = transactionId_;
+      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()) {
+          transactionId_ = s;
+        }
+        return s;
+      }
+    }
+    /**
+     * <code>required string transactionId = 1;</code>
+     */
+    public com.google.protobuf.ByteString
+        getTransactionIdBytes() {
+      java.lang.Object ref = transactionId_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b =
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        transactionId_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
     private void initFields() {
+      transactionId_ = "";
     }
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
       byte isInitialized = memoizedIsInitialized;
       if (isInitialized != -1) return isInitialized == 1;
 
+      if (!hasTransactionId()) {
+        memoizedIsInitialized = 0;
+        return false;
+      }
       memoizedIsInitialized = 1;
       return true;
     }
@@ -827,6 +1067,9 @@ public final class ThreePhaseCommitCohortMessages {
     public void writeTo(com.google.protobuf.CodedOutputStream output)
                         throws java.io.IOException {
       getSerializedSize();
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        output.writeBytes(1, getTransactionIdBytes());
+      }
       getUnknownFields().writeTo(output);
     }
 
@@ -836,6 +1079,10 @@ public final class ThreePhaseCommitCohortMessages {
       if (size != -1) return size;
 
       size = 0;
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(1, getTransactionIdBytes());
+      }
       size += getUnknownFields().getSerializedSize();
       memoizedSerializedSize = size;
       return size;
@@ -952,6 +1199,8 @@ public final class ThreePhaseCommitCohortMessages {
 
       public Builder clear() {
         super.clear();
+        transactionId_ = "";
+        bitField0_ = (bitField0_ & ~0x00000001);
         return this;
       }
 
@@ -978,6 +1227,13 @@ public final class ThreePhaseCommitCohortMessages {
 
       public org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages.AbortTransaction buildPartial() {
         org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages.AbortTransaction result = new org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages.AbortTransaction(this);
+        int from_bitField0_ = bitField0_;
+        int to_bitField0_ = 0;
+        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
+          to_bitField0_ |= 0x00000001;
+        }
+        result.transactionId_ = transactionId_;
+        result.bitField0_ = to_bitField0_;
         onBuilt();
         return result;
       }
@@ -993,11 +1249,20 @@ public final class ThreePhaseCommitCohortMessages {
 
       public Builder mergeFrom(org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages.AbortTransaction other) {
         if (other == org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages.AbortTransaction.getDefaultInstance()) return this;
+        if (other.hasTransactionId()) {
+          bitField0_ |= 0x00000001;
+          transactionId_ = other.transactionId_;
+          onChanged();
+        }
         this.mergeUnknownFields(other.getUnknownFields());
         return this;
       }
 
       public final boolean isInitialized() {
+        if (!hasTransactionId()) {
+
+          return false;
+        }
         return true;
       }
 
@@ -1018,6 +1283,81 @@ public final class ThreePhaseCommitCohortMessages {
         }
         return this;
       }
+      private int bitField0_;
+
+      // required string transactionId = 1;
+      private java.lang.Object transactionId_ = "";
+      /**
+       * <code>required string transactionId = 1;</code>
+       */
+      public boolean hasTransactionId() {
+        return ((bitField0_ & 0x00000001) == 0x00000001);
+      }
+      /**
+       * <code>required string transactionId = 1;</code>
+       */
+      public java.lang.String getTransactionId() {
+        java.lang.Object ref = transactionId_;
+        if (!(ref instanceof java.lang.String)) {
+          java.lang.String s = ((com.google.protobuf.ByteString) ref)
+              .toStringUtf8();
+          transactionId_ = s;
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>required string transactionId = 1;</code>
+       */
+      public com.google.protobuf.ByteString
+          getTransactionIdBytes() {
+        java.lang.Object ref = transactionId_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b =
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          transactionId_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>required string transactionId = 1;</code>
+       */
+      public Builder setTransactionId(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000001;
+        transactionId_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>required string transactionId = 1;</code>
+       */
+      public Builder clearTransactionId() {
+        bitField0_ = (bitField0_ & ~0x00000001);
+        transactionId_ = getDefaultInstance().getTransactionId();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>required string transactionId = 1;</code>
+       */
+      public Builder setTransactionIdBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000001;
+        transactionId_ = value;
+        onChanged();
+        return this;
+      }
 
       // @@protoc_insertion_point(builder_scope:org.opendaylight.controller.mdsal.AbortTransaction)
     }
@@ -1341,6 +1681,21 @@ public final class ThreePhaseCommitCohortMessages {
 
   public interface CommitTransactionOrBuilder
       extends com.google.protobuf.MessageOrBuilder {
+
+    // required string transactionId = 1;
+    /**
+     * <code>required string transactionId = 1;</code>
+     */
+    boolean hasTransactionId();
+    /**
+     * <code>required string transactionId = 1;</code>
+     */
+    java.lang.String getTransactionId();
+    /**
+     * <code>required string transactionId = 1;</code>
+     */
+    com.google.protobuf.ByteString
+        getTransactionIdBytes();
   }
   /**
    * Protobuf type {@code org.opendaylight.controller.mdsal.CommitTransaction}
@@ -1375,6 +1730,7 @@ public final class ThreePhaseCommitCohortMessages {
         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 {
@@ -1392,6 +1748,11 @@ public final class ThreePhaseCommitCohortMessages {
               }
               break;
             }
+            case 10: {
+              bitField0_ |= 0x00000001;
+              transactionId_ = input.readBytes();
+              break;
+            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -1431,13 +1792,62 @@ public final class ThreePhaseCommitCohortMessages {
       return PARSER;
     }
 
+    private int bitField0_;
+    // required string transactionId = 1;
+    public static final int TRANSACTIONID_FIELD_NUMBER = 1;
+    private java.lang.Object transactionId_;
+    /**
+     * <code>required string transactionId = 1;</code>
+     */
+    public boolean hasTransactionId() {
+      return ((bitField0_ & 0x00000001) == 0x00000001);
+    }
+    /**
+     * <code>required string transactionId = 1;</code>
+     */
+    public java.lang.String getTransactionId() {
+      java.lang.Object ref = transactionId_;
+      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()) {
+          transactionId_ = s;
+        }
+        return s;
+      }
+    }
+    /**
+     * <code>required string transactionId = 1;</code>
+     */
+    public com.google.protobuf.ByteString
+        getTransactionIdBytes() {
+      java.lang.Object ref = transactionId_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b =
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        transactionId_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
     private void initFields() {
+      transactionId_ = "";
     }
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
       byte isInitialized = memoizedIsInitialized;
       if (isInitialized != -1) return isInitialized == 1;
 
+      if (!hasTransactionId()) {
+        memoizedIsInitialized = 0;
+        return false;
+      }
       memoizedIsInitialized = 1;
       return true;
     }
@@ -1445,6 +1855,9 @@ public final class ThreePhaseCommitCohortMessages {
     public void writeTo(com.google.protobuf.CodedOutputStream output)
                         throws java.io.IOException {
       getSerializedSize();
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        output.writeBytes(1, getTransactionIdBytes());
+      }
       getUnknownFields().writeTo(output);
     }
 
@@ -1454,6 +1867,10 @@ public final class ThreePhaseCommitCohortMessages {
       if (size != -1) return size;
 
       size = 0;
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(1, getTransactionIdBytes());
+      }
       size += getUnknownFields().getSerializedSize();
       memoizedSerializedSize = size;
       return size;
@@ -1570,6 +1987,8 @@ public final class ThreePhaseCommitCohortMessages {
 
       public Builder clear() {
         super.clear();
+        transactionId_ = "";
+        bitField0_ = (bitField0_ & ~0x00000001);
         return this;
       }
 
@@ -1596,6 +2015,13 @@ public final class ThreePhaseCommitCohortMessages {
 
       public org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages.CommitTransaction buildPartial() {
         org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages.CommitTransaction result = new org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages.CommitTransaction(this);
+        int from_bitField0_ = bitField0_;
+        int to_bitField0_ = 0;
+        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
+          to_bitField0_ |= 0x00000001;
+        }
+        result.transactionId_ = transactionId_;
+        result.bitField0_ = to_bitField0_;
         onBuilt();
         return result;
       }
@@ -1611,11 +2037,20 @@ public final class ThreePhaseCommitCohortMessages {
 
       public Builder mergeFrom(org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages.CommitTransaction other) {
         if (other == org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages.CommitTransaction.getDefaultInstance()) return this;
+        if (other.hasTransactionId()) {
+          bitField0_ |= 0x00000001;
+          transactionId_ = other.transactionId_;
+          onChanged();
+        }
         this.mergeUnknownFields(other.getUnknownFields());
         return this;
       }
 
       public final boolean isInitialized() {
+        if (!hasTransactionId()) {
+
+          return false;
+        }
         return true;
       }
 
@@ -1636,6 +2071,81 @@ public final class ThreePhaseCommitCohortMessages {
         }
         return this;
       }
+      private int bitField0_;
+
+      // required string transactionId = 1;
+      private java.lang.Object transactionId_ = "";
+      /**
+       * <code>required string transactionId = 1;</code>
+       */
+      public boolean hasTransactionId() {
+        return ((bitField0_ & 0x00000001) == 0x00000001);
+      }
+      /**
+       * <code>required string transactionId = 1;</code>
+       */
+      public java.lang.String getTransactionId() {
+        java.lang.Object ref = transactionId_;
+        if (!(ref instanceof java.lang.String)) {
+          java.lang.String s = ((com.google.protobuf.ByteString) ref)
+              .toStringUtf8();
+          transactionId_ = s;
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>required string transactionId = 1;</code>
+       */
+      public com.google.protobuf.ByteString
+          getTransactionIdBytes() {
+        java.lang.Object ref = transactionId_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b =
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          transactionId_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>required string transactionId = 1;</code>
+       */
+      public Builder setTransactionId(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000001;
+        transactionId_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>required string transactionId = 1;</code>
+       */
+      public Builder clearTransactionId() {
+        bitField0_ = (bitField0_ & ~0x00000001);
+        transactionId_ = getDefaultInstance().getTransactionId();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>required string transactionId = 1;</code>
+       */
+      public Builder setTransactionIdBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000001;
+        transactionId_ = value;
+        onChanged();
+        return this;
+      }
 
       // @@protoc_insertion_point(builder_scope:org.opendaylight.controller.mdsal.CommitTransaction)
     }
@@ -2625,14 +3135,16 @@ public final class ThreePhaseCommitCohortMessages {
   static {
     java.lang.String[] descriptorData = {
       "\n\014Cohort.proto\022!org.opendaylight.control" +
-      "ler.mdsal\"\026\n\024CanCommitTransaction\".\n\031Can" +
-      "CommitTransactionReply\022\021\n\tcanCommit\030\001 \002(" +
-      "\010\"\022\n\020AbortTransaction\"\027\n\025AbortTransactio" +
-      "nReply\"\023\n\021CommitTransaction\"\030\n\026CommitTra" +
-      "nsactionReply\"\026\n\024PreCommitTransaction\"\033\n" +
-      "\031PreCommitTransactionReplyBZ\n8org.openda" +
-      "ylight.controller.protobuff.messages.coh" +
-      "ort3pcB\036ThreePhaseCommitCohortMessages"
+      "ler.mdsal\"-\n\024CanCommitTransaction\022\025\n\rtra" +
+      "nsactionId\030\001 \002(\t\".\n\031CanCommitTransaction" +
+      "Reply\022\021\n\tcanCommit\030\001 \002(\010\")\n\020AbortTransac" +
+      "tion\022\025\n\rtransactionId\030\001 \002(\t\"\027\n\025AbortTran" +
+      "sactionReply\"*\n\021CommitTransaction\022\025\n\rtra" +
+      "nsactionId\030\001 \002(\t\"\030\n\026CommitTransactionRep" +
+      "ly\"\026\n\024PreCommitTransaction\"\033\n\031PreCommitT" +
+      "ransactionReplyBZ\n8org.opendaylight.cont" +
+      "roller.protobuff.messages.cohort3pcB\036Thr",
+      "eePhaseCommitCohortMessages"
     };
     com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
       new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
@@ -2644,7 +3156,7 @@ public final class ThreePhaseCommitCohortMessages {
           internal_static_org_opendaylight_controller_mdsal_CanCommitTransaction_fieldAccessorTable = new
             com.google.protobuf.GeneratedMessage.FieldAccessorTable(
               internal_static_org_opendaylight_controller_mdsal_CanCommitTransaction_descriptor,
-              new java.lang.String[] { });
+              new java.lang.String[] { "TransactionId", });
           internal_static_org_opendaylight_controller_mdsal_CanCommitTransactionReply_descriptor =
             getDescriptor().getMessageTypes().get(1);
           internal_static_org_opendaylight_controller_mdsal_CanCommitTransactionReply_fieldAccessorTable = new
@@ -2656,7 +3168,7 @@ public final class ThreePhaseCommitCohortMessages {
           internal_static_org_opendaylight_controller_mdsal_AbortTransaction_fieldAccessorTable = new
             com.google.protobuf.GeneratedMessage.FieldAccessorTable(
               internal_static_org_opendaylight_controller_mdsal_AbortTransaction_descriptor,
-              new java.lang.String[] { });
+              new java.lang.String[] { "TransactionId", });
           internal_static_org_opendaylight_controller_mdsal_AbortTransactionReply_descriptor =
             getDescriptor().getMessageTypes().get(3);
           internal_static_org_opendaylight_controller_mdsal_AbortTransactionReply_fieldAccessorTable = new
@@ -2668,7 +3180,7 @@ public final class ThreePhaseCommitCohortMessages {
           internal_static_org_opendaylight_controller_mdsal_CommitTransaction_fieldAccessorTable = new
             com.google.protobuf.GeneratedMessage.FieldAccessorTable(
               internal_static_org_opendaylight_controller_mdsal_CommitTransaction_descriptor,
-              new java.lang.String[] { });
+              new java.lang.String[] { "TransactionId", });
           internal_static_org_opendaylight_controller_mdsal_CommitTransactionReply_descriptor =
             getDescriptor().getMessageTypes().get(5);
           internal_static_org_opendaylight_controller_mdsal_CommitTransactionReply_fieldAccessorTable = new
index d956bb174be4e159bc3fe0b415126ea39a4ba140..feb60ae829d418b200300cba4faecc42cca5f942 100644 (file)
@@ -788,794 +788,6 @@ public final class ShardTransactionChainMessages {
     // @@protoc_insertion_point(class_scope:org.opendaylight.controller.mdsal.CloseTransactionChainReply)
   }
 
-  public interface CreateTransactionChainOrBuilder
-      extends com.google.protobuf.MessageOrBuilder {
-  }
-  /**
-   * Protobuf type {@code org.opendaylight.controller.mdsal.CreateTransactionChain}
-   */
-  public static final class CreateTransactionChain extends
-      com.google.protobuf.GeneratedMessage
-      implements CreateTransactionChainOrBuilder {
-    // Use CreateTransactionChain.newBuilder() to construct.
-    private CreateTransactionChain(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
-      super(builder);
-      this.unknownFields = builder.getUnknownFields();
-    }
-    private CreateTransactionChain(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }
-
-    private static final CreateTransactionChain defaultInstance;
-    public static CreateTransactionChain getDefaultInstance() {
-      return defaultInstance;
-    }
-
-    public CreateTransactionChain getDefaultInstanceForType() {
-      return defaultInstance;
-    }
-
-    private final com.google.protobuf.UnknownFieldSet unknownFields;
-    @java.lang.Override
-    public final com.google.protobuf.UnknownFieldSet
-        getUnknownFields() {
-      return this.unknownFields;
-    }
-    private CreateTransactionChain(
-        com.google.protobuf.CodedInputStream input,
-        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
-        throws com.google.protobuf.InvalidProtocolBufferException {
-      initFields();
-      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;
-            }
-          }
-        }
-      } 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.protobuff.messages.transaction.ShardTransactionChainMessages.internal_static_org_opendaylight_controller_mdsal_CreateTransactionChain_descriptor;
-    }
-
-    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
-        internalGetFieldAccessorTable() {
-      return org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.internal_static_org_opendaylight_controller_mdsal_CreateTransactionChain_fieldAccessorTable
-          .ensureFieldAccessorsInitialized(
-              org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain.class, org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain.Builder.class);
-    }
-
-    public static com.google.protobuf.Parser<CreateTransactionChain> PARSER =
-        new com.google.protobuf.AbstractParser<CreateTransactionChain>() {
-      public CreateTransactionChain parsePartialFrom(
-          com.google.protobuf.CodedInputStream input,
-          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
-          throws com.google.protobuf.InvalidProtocolBufferException {
-        return new CreateTransactionChain(input, extensionRegistry);
-      }
-    };
-
-    @java.lang.Override
-    public com.google.protobuf.Parser<CreateTransactionChain> getParserForType() {
-      return PARSER;
-    }
-
-    private void initFields() {
-    }
-    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();
-      getUnknownFields().writeTo(output);
-    }
-
-    private int memoizedSerializedSize = -1;
-    public int getSerializedSize() {
-      int size = memoizedSerializedSize;
-      if (size != -1) return size;
-
-      size = 0;
-      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.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain parseFrom(
-        com.google.protobuf.ByteString data)
-        throws com.google.protobuf.InvalidProtocolBufferException {
-      return PARSER.parseFrom(data);
-    }
-    public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain 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.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain parseFrom(byte[] data)
-        throws com.google.protobuf.InvalidProtocolBufferException {
-      return PARSER.parseFrom(data);
-    }
-    public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain parseFrom(
-        byte[] data,
-        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
-        throws com.google.protobuf.InvalidProtocolBufferException {
-      return PARSER.parseFrom(data, extensionRegistry);
-    }
-    public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain parseFrom(java.io.InputStream input)
-        throws java.io.IOException {
-      return PARSER.parseFrom(input);
-    }
-    public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain parseFrom(
-        java.io.InputStream input,
-        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
-        throws java.io.IOException {
-      return PARSER.parseFrom(input, extensionRegistry);
-    }
-    public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain parseDelimitedFrom(java.io.InputStream input)
-        throws java.io.IOException {
-      return PARSER.parseDelimitedFrom(input);
-    }
-    public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain parseDelimitedFrom(
-        java.io.InputStream input,
-        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
-        throws java.io.IOException {
-      return PARSER.parseDelimitedFrom(input, extensionRegistry);
-    }
-    public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain parseFrom(
-        com.google.protobuf.CodedInputStream input)
-        throws java.io.IOException {
-      return PARSER.parseFrom(input);
-    }
-    public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain 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.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain 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.mdsal.CreateTransactionChain}
-     */
-    public static final class Builder extends
-        com.google.protobuf.GeneratedMessage.Builder<Builder>
-       implements org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainOrBuilder {
-      public static final com.google.protobuf.Descriptors.Descriptor
-          getDescriptor() {
-        return org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.internal_static_org_opendaylight_controller_mdsal_CreateTransactionChain_descriptor;
-      }
-
-      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
-          internalGetFieldAccessorTable() {
-        return org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.internal_static_org_opendaylight_controller_mdsal_CreateTransactionChain_fieldAccessorTable
-            .ensureFieldAccessorsInitialized(
-                org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain.class, org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain.Builder.class);
-      }
-
-      // Construct using org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain.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();
-        return this;
-      }
-
-      public Builder clone() {
-        return create().mergeFrom(buildPartial());
-      }
-
-      public com.google.protobuf.Descriptors.Descriptor
-          getDescriptorForType() {
-        return org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.internal_static_org_opendaylight_controller_mdsal_CreateTransactionChain_descriptor;
-      }
-
-      public org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain getDefaultInstanceForType() {
-        return org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain.getDefaultInstance();
-      }
-
-      public org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain build() {
-        org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain result = buildPartial();
-        if (!result.isInitialized()) {
-          throw newUninitializedMessageException(result);
-        }
-        return result;
-      }
-
-      public org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain buildPartial() {
-        org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain result = new org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain(this);
-        onBuilt();
-        return result;
-      }
-
-      public Builder mergeFrom(com.google.protobuf.Message other) {
-        if (other instanceof org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain) {
-          return mergeFrom((org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain)other);
-        } else {
-          super.mergeFrom(other);
-          return this;
-        }
-      }
-
-      public Builder mergeFrom(org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain other) {
-        if (other == org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain.getDefaultInstance()) return this;
-        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.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain parsedMessage = null;
-        try {
-          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
-        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
-          parsedMessage = (org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChain) e.getUnfinishedMessage();
-          throw e;
-        } finally {
-          if (parsedMessage != null) {
-            mergeFrom(parsedMessage);
-          }
-        }
-        return this;
-      }
-
-      // @@protoc_insertion_point(builder_scope:org.opendaylight.controller.mdsal.CreateTransactionChain)
-    }
-
-    static {
-      defaultInstance = new CreateTransactionChain(true);
-      defaultInstance.initFields();
-    }
-
-    // @@protoc_insertion_point(class_scope:org.opendaylight.controller.mdsal.CreateTransactionChain)
-  }
-
-  public interface CreateTransactionChainReplyOrBuilder
-      extends com.google.protobuf.MessageOrBuilder {
-
-    // required string transactionChainPath = 1;
-    /**
-     * <code>required string transactionChainPath = 1;</code>
-     */
-    boolean hasTransactionChainPath();
-    /**
-     * <code>required string transactionChainPath = 1;</code>
-     */
-    java.lang.String getTransactionChainPath();
-    /**
-     * <code>required string transactionChainPath = 1;</code>
-     */
-    com.google.protobuf.ByteString
-        getTransactionChainPathBytes();
-  }
-  /**
-   * Protobuf type {@code org.opendaylight.controller.mdsal.CreateTransactionChainReply}
-   */
-  public static final class CreateTransactionChainReply extends
-      com.google.protobuf.GeneratedMessage
-      implements CreateTransactionChainReplyOrBuilder {
-    // Use CreateTransactionChainReply.newBuilder() to construct.
-    private CreateTransactionChainReply(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
-      super(builder);
-      this.unknownFields = builder.getUnknownFields();
-    }
-    private CreateTransactionChainReply(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }
-
-    private static final CreateTransactionChainReply defaultInstance;
-    public static CreateTransactionChainReply getDefaultInstance() {
-      return defaultInstance;
-    }
-
-    public CreateTransactionChainReply getDefaultInstanceForType() {
-      return defaultInstance;
-    }
-
-    private final com.google.protobuf.UnknownFieldSet unknownFields;
-    @java.lang.Override
-    public final com.google.protobuf.UnknownFieldSet
-        getUnknownFields() {
-      return this.unknownFields;
-    }
-    private CreateTransactionChainReply(
-        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 10: {
-              bitField0_ |= 0x00000001;
-              transactionChainPath_ = input.readBytes();
-              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.protobuff.messages.transaction.ShardTransactionChainMessages.internal_static_org_opendaylight_controller_mdsal_CreateTransactionChainReply_descriptor;
-    }
-
-    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
-        internalGetFieldAccessorTable() {
-      return org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.internal_static_org_opendaylight_controller_mdsal_CreateTransactionChainReply_fieldAccessorTable
-          .ensureFieldAccessorsInitialized(
-              org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply.class, org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply.Builder.class);
-    }
-
-    public static com.google.protobuf.Parser<CreateTransactionChainReply> PARSER =
-        new com.google.protobuf.AbstractParser<CreateTransactionChainReply>() {
-      public CreateTransactionChainReply parsePartialFrom(
-          com.google.protobuf.CodedInputStream input,
-          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
-          throws com.google.protobuf.InvalidProtocolBufferException {
-        return new CreateTransactionChainReply(input, extensionRegistry);
-      }
-    };
-
-    @java.lang.Override
-    public com.google.protobuf.Parser<CreateTransactionChainReply> getParserForType() {
-      return PARSER;
-    }
-
-    private int bitField0_;
-    // required string transactionChainPath = 1;
-    public static final int TRANSACTIONCHAINPATH_FIELD_NUMBER = 1;
-    private java.lang.Object transactionChainPath_;
-    /**
-     * <code>required string transactionChainPath = 1;</code>
-     */
-    public boolean hasTransactionChainPath() {
-      return ((bitField0_ & 0x00000001) == 0x00000001);
-    }
-    /**
-     * <code>required string transactionChainPath = 1;</code>
-     */
-    public java.lang.String getTransactionChainPath() {
-      java.lang.Object ref = transactionChainPath_;
-      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()) {
-          transactionChainPath_ = s;
-        }
-        return s;
-      }
-    }
-    /**
-     * <code>required string transactionChainPath = 1;</code>
-     */
-    public com.google.protobuf.ByteString
-        getTransactionChainPathBytes() {
-      java.lang.Object ref = transactionChainPath_;
-      if (ref instanceof java.lang.String) {
-        com.google.protobuf.ByteString b =
-            com.google.protobuf.ByteString.copyFromUtf8(
-                (java.lang.String) ref);
-        transactionChainPath_ = b;
-        return b;
-      } else {
-        return (com.google.protobuf.ByteString) ref;
-      }
-    }
-
-    private void initFields() {
-      transactionChainPath_ = "";
-    }
-    private byte memoizedIsInitialized = -1;
-    public final boolean isInitialized() {
-      byte isInitialized = memoizedIsInitialized;
-      if (isInitialized != -1) return isInitialized == 1;
-
-      if (!hasTransactionChainPath()) {
-        memoizedIsInitialized = 0;
-        return false;
-      }
-      memoizedIsInitialized = 1;
-      return true;
-    }
-
-    public void writeTo(com.google.protobuf.CodedOutputStream output)
-                        throws java.io.IOException {
-      getSerializedSize();
-      if (((bitField0_ & 0x00000001) == 0x00000001)) {
-        output.writeBytes(1, getTransactionChainPathBytes());
-      }
-      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
-          .computeBytesSize(1, getTransactionChainPathBytes());
-      }
-      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.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply parseFrom(
-        com.google.protobuf.ByteString data)
-        throws com.google.protobuf.InvalidProtocolBufferException {
-      return PARSER.parseFrom(data);
-    }
-    public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply 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.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply parseFrom(byte[] data)
-        throws com.google.protobuf.InvalidProtocolBufferException {
-      return PARSER.parseFrom(data);
-    }
-    public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply parseFrom(
-        byte[] data,
-        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
-        throws com.google.protobuf.InvalidProtocolBufferException {
-      return PARSER.parseFrom(data, extensionRegistry);
-    }
-    public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply parseFrom(java.io.InputStream input)
-        throws java.io.IOException {
-      return PARSER.parseFrom(input);
-    }
-    public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply parseFrom(
-        java.io.InputStream input,
-        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
-        throws java.io.IOException {
-      return PARSER.parseFrom(input, extensionRegistry);
-    }
-    public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply parseDelimitedFrom(java.io.InputStream input)
-        throws java.io.IOException {
-      return PARSER.parseDelimitedFrom(input);
-    }
-    public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply parseDelimitedFrom(
-        java.io.InputStream input,
-        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
-        throws java.io.IOException {
-      return PARSER.parseDelimitedFrom(input, extensionRegistry);
-    }
-    public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply parseFrom(
-        com.google.protobuf.CodedInputStream input)
-        throws java.io.IOException {
-      return PARSER.parseFrom(input);
-    }
-    public static org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply 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.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply 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.mdsal.CreateTransactionChainReply}
-     */
-    public static final class Builder extends
-        com.google.protobuf.GeneratedMessage.Builder<Builder>
-       implements org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReplyOrBuilder {
-      public static final com.google.protobuf.Descriptors.Descriptor
-          getDescriptor() {
-        return org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.internal_static_org_opendaylight_controller_mdsal_CreateTransactionChainReply_descriptor;
-      }
-
-      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
-          internalGetFieldAccessorTable() {
-        return org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.internal_static_org_opendaylight_controller_mdsal_CreateTransactionChainReply_fieldAccessorTable
-            .ensureFieldAccessorsInitialized(
-                org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply.class, org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply.Builder.class);
-      }
-
-      // Construct using org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply.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();
-        transactionChainPath_ = "";
-        bitField0_ = (bitField0_ & ~0x00000001);
-        return this;
-      }
-
-      public Builder clone() {
-        return create().mergeFrom(buildPartial());
-      }
-
-      public com.google.protobuf.Descriptors.Descriptor
-          getDescriptorForType() {
-        return org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.internal_static_org_opendaylight_controller_mdsal_CreateTransactionChainReply_descriptor;
-      }
-
-      public org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply getDefaultInstanceForType() {
-        return org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply.getDefaultInstance();
-      }
-
-      public org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply build() {
-        org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply result = buildPartial();
-        if (!result.isInitialized()) {
-          throw newUninitializedMessageException(result);
-        }
-        return result;
-      }
-
-      public org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply buildPartial() {
-        org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply result = new org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply(this);
-        int from_bitField0_ = bitField0_;
-        int to_bitField0_ = 0;
-        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
-          to_bitField0_ |= 0x00000001;
-        }
-        result.transactionChainPath_ = transactionChainPath_;
-        result.bitField0_ = to_bitField0_;
-        onBuilt();
-        return result;
-      }
-
-      public Builder mergeFrom(com.google.protobuf.Message other) {
-        if (other instanceof org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply) {
-          return mergeFrom((org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply)other);
-        } else {
-          super.mergeFrom(other);
-          return this;
-        }
-      }
-
-      public Builder mergeFrom(org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply other) {
-        if (other == org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply.getDefaultInstance()) return this;
-        if (other.hasTransactionChainPath()) {
-          bitField0_ |= 0x00000001;
-          transactionChainPath_ = other.transactionChainPath_;
-          onChanged();
-        }
-        this.mergeUnknownFields(other.getUnknownFields());
-        return this;
-      }
-
-      public final boolean isInitialized() {
-        if (!hasTransactionChainPath()) {
-
-          return false;
-        }
-        return true;
-      }
-
-      public Builder mergeFrom(
-          com.google.protobuf.CodedInputStream input,
-          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
-          throws java.io.IOException {
-        org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply parsedMessage = null;
-        try {
-          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
-        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
-          parsedMessage = (org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages.CreateTransactionChainReply) e.getUnfinishedMessage();
-          throw e;
-        } finally {
-          if (parsedMessage != null) {
-            mergeFrom(parsedMessage);
-          }
-        }
-        return this;
-      }
-      private int bitField0_;
-
-      // required string transactionChainPath = 1;
-      private java.lang.Object transactionChainPath_ = "";
-      /**
-       * <code>required string transactionChainPath = 1;</code>
-       */
-      public boolean hasTransactionChainPath() {
-        return ((bitField0_ & 0x00000001) == 0x00000001);
-      }
-      /**
-       * <code>required string transactionChainPath = 1;</code>
-       */
-      public java.lang.String getTransactionChainPath() {
-        java.lang.Object ref = transactionChainPath_;
-        if (!(ref instanceof java.lang.String)) {
-          java.lang.String s = ((com.google.protobuf.ByteString) ref)
-              .toStringUtf8();
-          transactionChainPath_ = s;
-          return s;
-        } else {
-          return (java.lang.String) ref;
-        }
-      }
-      /**
-       * <code>required string transactionChainPath = 1;</code>
-       */
-      public com.google.protobuf.ByteString
-          getTransactionChainPathBytes() {
-        java.lang.Object ref = transactionChainPath_;
-        if (ref instanceof String) {
-          com.google.protobuf.ByteString b =
-              com.google.protobuf.ByteString.copyFromUtf8(
-                  (java.lang.String) ref);
-          transactionChainPath_ = b;
-          return b;
-        } else {
-          return (com.google.protobuf.ByteString) ref;
-        }
-      }
-      /**
-       * <code>required string transactionChainPath = 1;</code>
-       */
-      public Builder setTransactionChainPath(
-          java.lang.String value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00000001;
-        transactionChainPath_ = value;
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>required string transactionChainPath = 1;</code>
-       */
-      public Builder clearTransactionChainPath() {
-        bitField0_ = (bitField0_ & ~0x00000001);
-        transactionChainPath_ = getDefaultInstance().getTransactionChainPath();
-        onChanged();
-        return this;
-      }
-      /**
-       * <code>required string transactionChainPath = 1;</code>
-       */
-      public Builder setTransactionChainPathBytes(
-          com.google.protobuf.ByteString value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  bitField0_ |= 0x00000001;
-        transactionChainPath_ = value;
-        onChanged();
-        return this;
-      }
-
-      // @@protoc_insertion_point(builder_scope:org.opendaylight.controller.mdsal.CreateTransactionChainReply)
-    }
-
-    static {
-      defaultInstance = new CreateTransactionChainReply(true);
-      defaultInstance.initFields();
-    }
-
-    // @@protoc_insertion_point(class_scope:org.opendaylight.controller.mdsal.CreateTransactionChainReply)
-  }
-
   private static com.google.protobuf.Descriptors.Descriptor
     internal_static_org_opendaylight_controller_mdsal_CloseTransactionChain_descriptor;
   private static
@@ -1586,16 +798,6 @@ public final class ShardTransactionChainMessages {
   private static
     com.google.protobuf.GeneratedMessage.FieldAccessorTable
       internal_static_org_opendaylight_controller_mdsal_CloseTransactionChainReply_fieldAccessorTable;
-  private static com.google.protobuf.Descriptors.Descriptor
-    internal_static_org_opendaylight_controller_mdsal_CreateTransactionChain_descriptor;
-  private static
-    com.google.protobuf.GeneratedMessage.FieldAccessorTable
-      internal_static_org_opendaylight_controller_mdsal_CreateTransactionChain_fieldAccessorTable;
-  private static com.google.protobuf.Descriptors.Descriptor
-    internal_static_org_opendaylight_controller_mdsal_CreateTransactionChainReply_descriptor;
-  private static
-    com.google.protobuf.GeneratedMessage.FieldAccessorTable
-      internal_static_org_opendaylight_controller_mdsal_CreateTransactionChainReply_fieldAccessorTable;
 
   public static com.google.protobuf.Descriptors.FileDescriptor
       getDescriptor() {
@@ -1608,12 +810,9 @@ public final class ShardTransactionChainMessages {
       "\n\033ShardTransactionChain.proto\022!org.opend" +
       "aylight.controller.mdsal\"3\n\025CloseTransac" +
       "tionChain\022\032\n\022transactionChainId\030\001 \001(\t\"\034\n" +
-      "\032CloseTransactionChainReply\"\030\n\026CreateTra" +
-      "nsactionChain\";\n\033CreateTransactionChainR" +
-      "eply\022\034\n\024transactionChainPath\030\001 \002(\tB[\n:or" +
-      "g.opendaylight.controller.protobuff.mess" +
-      "ages.transactionB\035ShardTransactionChainM" +
-      "essages"
+      "\032CloseTransactionChainReplyB[\n:org.opend" +
+      "aylight.controller.protobuff.messages.tr" +
+      "ansactionB\035ShardTransactionChainMessages"
     };
     com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
       new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
@@ -1632,18 +831,6 @@ public final class ShardTransactionChainMessages {
             com.google.protobuf.GeneratedMessage.FieldAccessorTable(
               internal_static_org_opendaylight_controller_mdsal_CloseTransactionChainReply_descriptor,
               new java.lang.String[] { });
-          internal_static_org_opendaylight_controller_mdsal_CreateTransactionChain_descriptor =
-            getDescriptor().getMessageTypes().get(2);
-          internal_static_org_opendaylight_controller_mdsal_CreateTransactionChain_fieldAccessorTable = new
-            com.google.protobuf.GeneratedMessage.FieldAccessorTable(
-              internal_static_org_opendaylight_controller_mdsal_CreateTransactionChain_descriptor,
-              new java.lang.String[] { });
-          internal_static_org_opendaylight_controller_mdsal_CreateTransactionChainReply_descriptor =
-            getDescriptor().getMessageTypes().get(3);
-          internal_static_org_opendaylight_controller_mdsal_CreateTransactionChainReply_fieldAccessorTable = new
-            com.google.protobuf.GeneratedMessage.FieldAccessorTable(
-              internal_static_org_opendaylight_controller_mdsal_CreateTransactionChainReply_descriptor,
-              new java.lang.String[] { "TransactionChainPath", });
           return null;
         }
       };
index dab64131e63fb6b127a10c6e618114cd9b79940d..49c6cd07a866199415116349041a9defe039d18c 100644 (file)
@@ -5,7 +5,7 @@ option java_outer_classname = "ThreePhaseCommitCohortMessages";
 
 
 message CanCommitTransaction{
-
+  required string transactionId = 1;
 }
 
 message CanCommitTransactionReply{
@@ -14,7 +14,7 @@ message CanCommitTransactionReply{
 }
 
 message AbortTransaction{
-
+  required string transactionId = 1;
 }
 
 message AbortTransactionReply {
@@ -22,7 +22,7 @@ message AbortTransactionReply {
 }
 
 message CommitTransaction{
-
+  required string transactionId = 1;
 }
 
 message CommitTransactionReply{
diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/util/NormalizedNodeXmlConverterTest.java b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/util/NormalizedNodeXmlConverterTest.java
deleted file mode 100644 (file)
index 853b3e2..0000000
+++ /dev/null
@@ -1,483 +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.cluster.datastore.util;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import org.custommonkey.xmlunit.Diff;
-import org.custommonkey.xmlunit.XMLUnit;
-import org.junit.Test;
-import org.opendaylight.controller.protobuff.messages.common.SimpleNormalizedNodeMessage;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
-import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
-import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
-import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils;
-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.DataContainerNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils;
-import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory;
-import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.serializer.DomFromNormalizedNodeSerializerFactory;
-import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
-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.Module;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.xml.sax.SAXException;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.TransformerFactoryConfigurationError;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.StringWriter;
-import java.net.URI;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-
-/**
- * Two of the testcases in the yangtools/yang-data-impl are leveraged (with modification) to create
- * the serialization of NormalizedNode using the ProtocolBuffer
- *
- * @syedbahm
- *
- */
-
-
-public class NormalizedNodeXmlConverterTest {
-  private static final Logger logger = LoggerFactory
-      .getLogger(NormalizedNodeXmlConverterTest.class);
-  public static final String NAMESPACE =
-      "urn:opendaylight:params:xml:ns:yang:controller:test";
-  private static Date revision;
-  private ContainerNode expectedNode;
-  private ContainerSchemaNode containerNode;
-  private String xmlPath;
-
-  static {
-    try {
-      revision = new SimpleDateFormat("yyyy-MM-dd").parse("2014-03-13");
-    } catch (ParseException e) {
-      throw new RuntimeException(e);
-    }
-  }
-
-  public static DataSchemaNode getSchemaNode(final SchemaContext context,
-      final String moduleName, final String childNodeName) {
-    for (Module module : context.getModules()) {
-      if (module.getName().equals(moduleName)) {
-        DataSchemaNode found =
-            findChildNode(module.getChildNodes(), childNodeName);
-        Preconditions.checkState(found != null, "Unable to find %s",
-            childNodeName);
-        return found;
-      }
-    }
-    throw new IllegalStateException("Unable to find child node "
-        + childNodeName);
-  }
-
-  static DataSchemaNode findChildNode(
-      final Collection<DataSchemaNode> children, final String name) {
-    List<DataNodeContainer> containers = Lists.newArrayList();
-
-    for (DataSchemaNode dataSchemaNode : children) {
-      if (dataSchemaNode.getQName().getLocalName().equals(name)) {
-        return dataSchemaNode;
-      }
-      if (dataSchemaNode instanceof DataNodeContainer) {
-        containers.add((DataNodeContainer) dataSchemaNode);
-      } else if (dataSchemaNode instanceof ChoiceNode) {
-        containers.addAll(((ChoiceNode) dataSchemaNode).getCases());
-      }
-    }
-
-    for (DataNodeContainer container : containers) {
-      DataSchemaNode retVal = findChildNode(container.getChildNodes(), name);
-      if (retVal != null) {
-        return retVal;
-      }
-    }
-
-    return null;
-  }
-
-  public static YangInstanceIdentifier.NodeIdentifier getNodeIdentifier(
-      final String localName) {
-    return new YangInstanceIdentifier.NodeIdentifier(QName.create(
-        URI.create(NAMESPACE), revision, localName));
-  }
-
-  public static YangInstanceIdentifier.AugmentationIdentifier getAugmentIdentifier(
-      final String... childNames) {
-    Set<QName> qn = Sets.newHashSet();
-
-    for (String childName : childNames) {
-      qn.add(getNodeIdentifier(childName).getNodeType());
-    }
-
-    return new YangInstanceIdentifier.AugmentationIdentifier(qn);
-  }
-
-
-  public static ContainerNode augmentChoiceExpectedNode() {
-
-    DataContainerNodeBuilder<YangInstanceIdentifier.NodeIdentifier, ContainerNode> b =
-        Builders.containerBuilder();
-    b.withNodeIdentifier(getNodeIdentifier("container"));
-
-    b.withChild(Builders
-        .choiceBuilder()
-        .withNodeIdentifier(getNodeIdentifier("ch2"))
-        .withChild(
-            Builders.leafBuilder()
-                .withNodeIdentifier(getNodeIdentifier("c2Leaf")).withValue("2")
-                .build())
-        .withChild(
-            Builders
-                .choiceBuilder()
-                .withNodeIdentifier(getNodeIdentifier("c2DeepChoice"))
-                .withChild(
-                    Builders
-                        .leafBuilder()
-                        .withNodeIdentifier(
-                            getNodeIdentifier("c2DeepChoiceCase1Leaf2"))
-                        .withValue("2").build()).build()).build());
-
-    b.withChild(Builders
-        .choiceBuilder()
-        .withNodeIdentifier(getNodeIdentifier("ch3"))
-        .withChild(
-            Builders.leafBuilder()
-                .withNodeIdentifier(getNodeIdentifier("c3Leaf")).withValue("3")
-                .build()).build());
-
-    b.withChild(Builders
-        .augmentationBuilder()
-        .withNodeIdentifier(getAugmentIdentifier("augLeaf"))
-        .withChild(
-            Builders.leafBuilder()
-                .withNodeIdentifier(getNodeIdentifier("augLeaf"))
-                .withValue("augment").build()).build());
-
-    b.withChild(Builders
-        .augmentationBuilder()
-        .withNodeIdentifier(getAugmentIdentifier("ch"))
-        .withChild(
-            Builders
-                .choiceBuilder()
-                .withNodeIdentifier(getNodeIdentifier("ch"))
-                .withChild(
-                    Builders.leafBuilder()
-                        .withNodeIdentifier(getNodeIdentifier("c1Leaf"))
-                        .withValue("1").build())
-                .withChild(
-                    Builders
-                        .augmentationBuilder()
-                        .withNodeIdentifier(
-                            getAugmentIdentifier("c1Leaf_AnotherAugment",
-                                "deepChoice"))
-                        .withChild(
-                            Builders
-                                .leafBuilder()
-                                .withNodeIdentifier(
-                                    getNodeIdentifier("c1Leaf_AnotherAugment"))
-                                .withValue("1").build())
-                        .withChild(
-                            Builders
-                                .choiceBuilder()
-                                .withNodeIdentifier(
-                                    getNodeIdentifier("deepChoice"))
-                                .withChild(
-                                    Builders
-                                        .leafBuilder()
-                                        .withNodeIdentifier(
-                                            getNodeIdentifier("deepLeafc1"))
-                                        .withValue("1").build()).build())
-                        .build()).build()).build());
-
-    return b.build();
-  }
-
-
-
-  public void init(final String yangPath, final String xmlPath,
-      final ContainerNode expectedNode) throws Exception {
-    SchemaContext schema = parseTestSchema(yangPath);
-    this.xmlPath = xmlPath;
-    this.containerNode =
-        (ContainerSchemaNode) getSchemaNode(schema, "test", "container");
-    this.expectedNode = expectedNode;
-  }
-
-  SchemaContext parseTestSchema(final String yangPath) throws Exception {
-
-    YangParserImpl yangParserImpl = new YangParserImpl();
-    InputStream stream =
-        NormalizedNodeXmlConverterTest.class.getResourceAsStream(yangPath);
-    ArrayList<InputStream> al = new ArrayList<InputStream>();
-    al.add(stream);
-    Set<Module> modules = yangParserImpl.parseYangModelsFromStreams(al);
-    return yangParserImpl.resolveSchemaContext(modules);
-
-  }
-
-
-  @Test
-  public void testConversionWithAugmentChoice() throws Exception {
-    init("/augment_choice.yang", "/augment_choice.xml",
-        augmentChoiceExpectedNode());
-    Document doc = loadDocument(xmlPath);
-
-    ContainerNode built =
-        DomToNormalizedNodeParserFactory
-            .getInstance(DomUtils.defaultValueCodecProvider())
-            .getContainerNodeParser()
-            .parse(Collections.singletonList(doc.getDocumentElement()),
-                containerNode);
-
-    if (expectedNode != null) {
-      junit.framework.Assert.assertEquals(expectedNode, built);
-    }
-
-    logger.info("{}", built);
-
-    Iterable<Element> els =
-        DomFromNormalizedNodeSerializerFactory
-            .getInstance(XmlDocumentUtils.getDocument(),
-                DomUtils.defaultValueCodecProvider())
-            .getContainerNodeSerializer().serialize(containerNode, built);
-
-    Element el = els.iterator().next();
-
-    XMLUnit.setIgnoreWhitespace(true);
-    XMLUnit.setIgnoreComments(true);
-
-    System.out.println(toString(doc.getDocumentElement()));
-    System.out.println(toString(el));
-
-    new Diff(XMLUnit.buildControlDocument(toString(doc.getDocumentElement())),
-        XMLUnit.buildTestDocument(toString(el))).similar();
-  }
-
-  private static ContainerNode listLeafListWithAttributes() {
-    DataContainerNodeBuilder<YangInstanceIdentifier.NodeIdentifier, ContainerNode> b =
-        Builders.containerBuilder();
-    b.withNodeIdentifier(getNodeIdentifier("container"));
-
-    CollectionNodeBuilder<MapEntryNode, MapNode> listBuilder =
-        Builders.mapBuilder().withNodeIdentifier(getNodeIdentifier("list"));
-
-    Map<QName, Object> predicates = Maps.newHashMap();
-    predicates.put(getNodeIdentifier("uint32InList").getNodeType(), 3L);
-
-    DataContainerNodeBuilder<YangInstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> list1Builder =
-        Builders.mapEntryBuilder().withNodeIdentifier(
-            new YangInstanceIdentifier.NodeIdentifierWithPredicates(
-                getNodeIdentifier("list").getNodeType(), predicates));
-    NormalizedNodeBuilder<YangInstanceIdentifier.NodeIdentifier, Object, LeafNode<Object>> uint32InListBuilder =
-        Builders.leafBuilder().withNodeIdentifier(
-            getNodeIdentifier("uint32InList"));
-
-    list1Builder.withChild(uint32InListBuilder.withValue(3L).build());
-
-    listBuilder.withChild(list1Builder.build());
-    b.withChild(listBuilder.build());
-
-    NormalizedNodeBuilder<YangInstanceIdentifier.NodeIdentifier, Object, LeafNode<Object>> booleanBuilder =
-        Builders.leafBuilder().withNodeIdentifier(getNodeIdentifier("boolean"));
-    booleanBuilder.withValue(false);
-    b.withChild(booleanBuilder.build());
-
-    ListNodeBuilder<Object, LeafSetEntryNode<Object>> leafListBuilder =
-        Builders.leafSetBuilder().withNodeIdentifier(
-            getNodeIdentifier("leafList"));
-
-    NormalizedNodeBuilder<YangInstanceIdentifier.NodeWithValue, Object, LeafSetEntryNode<Object>> leafList1Builder =
-        Builders.leafSetEntryBuilder().withNodeIdentifier(
-            new YangInstanceIdentifier.NodeWithValue(getNodeIdentifier(
-                "leafList").getNodeType(), "a"));
-
-    leafList1Builder.withValue("a");
-
-    leafListBuilder.withChild(leafList1Builder.build());
-    b.withChild(leafListBuilder.build());
-
-    return b.build();
-  }
-
-
-  @Test
-  public void testConversionWithAttributes() throws Exception {
-    init("/test.yang", "/simple_xml_with_attributes.xml",
-        listLeafListWithAttributes());
-    Document doc = loadDocument(xmlPath);
-
-    ContainerNode built =
-        DomToNormalizedNodeParserFactory
-            .getInstance(DomUtils.defaultValueCodecProvider())
-            .getContainerNodeParser()
-            .parse(Collections.singletonList(doc.getDocumentElement()),
-                containerNode);
-
-    if (expectedNode != null) {
-      junit.framework.Assert.assertEquals(expectedNode, built);
-    }
-
-    logger.info("{}", built);
-
-    Iterable<Element> els =
-        DomFromNormalizedNodeSerializerFactory
-            .getInstance(XmlDocumentUtils.getDocument(),
-                DomUtils.defaultValueCodecProvider())
-            .getContainerNodeSerializer().serialize(containerNode, built);
-
-    Element el = els.iterator().next();
-
-    XMLUnit.setIgnoreWhitespace(true);
-    XMLUnit.setIgnoreComments(true);
-
-    System.out.println(toString(doc.getDocumentElement()));
-    System.out.println(toString(el));
-
-    new Diff(XMLUnit.buildControlDocument(toString(doc.getDocumentElement())),
-        XMLUnit.buildTestDocument(toString(el))).similar();
-  }
-
-
-  private Document loadDocument(final String xmlPath) throws Exception {
-    InputStream resourceAsStream =
-        NormalizedNodeXmlConverterTest.class.getResourceAsStream(xmlPath);
-
-    Document currentConfigElement = readXmlToDocument(resourceAsStream);
-    Preconditions.checkNotNull(currentConfigElement);
-    return currentConfigElement;
-  }
-
-  private static final DocumentBuilderFactory BUILDERFACTORY;
-
-  static {
-    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-    factory.setNamespaceAware(true);
-    factory.setCoalescing(true);
-    factory.setIgnoringElementContentWhitespace(true);
-    factory.setIgnoringComments(true);
-    BUILDERFACTORY = factory;
-  }
-
-  private Document readXmlToDocument(final InputStream xmlContent)
-      throws IOException, SAXException {
-    DocumentBuilder dBuilder;
-    try {
-      dBuilder = BUILDERFACTORY.newDocumentBuilder();
-    } catch (ParserConfigurationException e) {
-      throw new RuntimeException("Failed to parse XML document", e);
-    }
-    Document doc = dBuilder.parse(xmlContent);
-
-    doc.getDocumentElement().normalize();
-    return doc;
-  }
-
-  public static String toString(final Element xml) {
-    try {
-      Transformer transformer =
-          TransformerFactory.newInstance().newTransformer();
-      transformer.setOutputProperty(OutputKeys.INDENT, "yes");
-
-      StreamResult result = new StreamResult(new StringWriter());
-      DOMSource source = new DOMSource(xml);
-      transformer.transform(source, result);
-
-      return result.getWriter().toString();
-    } catch (IllegalArgumentException | TransformerFactoryConfigurationError
-        | TransformerException e) {
-      throw new RuntimeException("Unable to serialize xml element " + xml, e);
-    }
-  }
-
-  @Test
-  public void testConversionToNormalizedXml() throws Exception {
-    SimpleNormalizedNodeMessage.NormalizedNodeXml nnXml =
-        EncoderDecoderUtil.encode(parseTestSchema("/augment_choice.yang"),
-            augmentChoiceExpectedNode());
-    Document expectedDoc = loadDocument("/augment_choice.xml");
-    Document convertedDoc =
-        EncoderDecoderUtil.factory.newDocumentBuilder().parse(
-            new ByteArrayInputStream(nnXml.getXmlString().getBytes("utf-8")));
-    System.out.println(toString(convertedDoc.getDocumentElement()));
-    XMLUnit.setIgnoreWhitespace(true);
-    XMLUnit.setIgnoreComments(true);
-    new Diff(XMLUnit.buildControlDocument(toString(expectedDoc
-        .getDocumentElement())),
-        XMLUnit.buildTestDocument(toString(convertedDoc.getDocumentElement())))
-        .similar();
-    System.out.println(toString(expectedDoc.getDocumentElement()));
-
-  }
-
-
-  @Test
-  public void testConversionFromXmlToNormalizedNode() throws Exception {
-    SimpleNormalizedNodeMessage.NormalizedNodeXml nnXml =
-        EncoderDecoderUtil.encode(parseTestSchema("/test.yang"),
-            listLeafListWithAttributes());
-    Document expectedDoc = loadDocument("/simple_xml_with_attributes.xml");
-    Document convertedDoc =
-        EncoderDecoderUtil.factory.newDocumentBuilder().parse(
-            new ByteArrayInputStream(nnXml.getXmlString().getBytes("utf-8")));
-    System.out.println(toString(convertedDoc.getDocumentElement()));
-    XMLUnit.setIgnoreWhitespace(true);
-    XMLUnit.setIgnoreComments(true);
-    new Diff(XMLUnit.buildControlDocument(toString(expectedDoc
-        .getDocumentElement())),
-        XMLUnit.buildTestDocument(toString(convertedDoc.getDocumentElement())))
-        .similar();
-    System.out.println(toString(expectedDoc.getDocumentElement()));
-
-    // now we will try to convert xml back to normalize node.
-    ContainerNode cn =
-        (ContainerNode) EncoderDecoderUtil.decode(
-            parseTestSchema("/test.yang"), nnXml);
-    junit.framework.Assert.assertEquals(listLeafListWithAttributes(), cn);
-
-  }
-
-}
index c0e91ab0d0bfc58f10c66529fdbc73d89000e463..dba8f4f95aa249ced73e7c76b026ecbd6a1bdd41 100644 (file)
 
 package org.opendaylight.controller.protobuff.messages.transaction;
 
-import org.junit.Assert;
 import org.junit.Test;
 import org.opendaylight.controller.protobuff.messages.AbstractMessagesTest;
-import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages;
-import org.opendaylight.yangtools.yang.common.QName;
 
 /**
  * This test case is present to ensure that if others have used proper version of protocol buffer
@@ -34,29 +31,6 @@ public class ShardTransactionChainMessagesTest extends AbstractMessagesTest {
   @Override
   @Test
   public void verifySerialization() throws Exception {
-    String testTransactionChainPath =
-        "/actor/path";
-
-    ShardTransactionChainMessages.CreateTransactionChainReply.Builder builder =
-        ShardTransactionChainMessages.CreateTransactionChainReply.newBuilder();
-    builder.setTransactionChainPath(testTransactionChainPath);
-
-    writeToFile((com.google.protobuf.GeneratedMessage.Builder<?>) builder);
-
-    // Here we will read the same and check we got back what we had saved
-    ShardTransactionChainMessages.CreateTransactionChainReply replyNew =
-        (ShardTransactionChainMessages.CreateTransactionChainReply) readFromFile(ShardTransactionChainMessages.CreateTransactionChainReply.PARSER);
-
-    Assert.assertEquals(replyNew.getTransactionChainPath(),testTransactionChainPath);
-
-    // the following will compare with the version we had shipped
-    ShardTransactionChainMessages.CreateTransactionChainReply replyOriginal =
-        (ShardTransactionChainMessages.CreateTransactionChainReply) readFromTestDataFile(ShardTransactionChainMessages.CreateTransactionChainReply.PARSER);
-
-
-    Assert.assertEquals(replyOriginal.getTransactionChainPath(),
-        replyNew.getTransactionChainPath());
-
   }
 
   @Override
index fbb666a9caab32c90646796078132d1ed13c8bfa..b57a3f5f0bede2b7d93a880150818251f6247b14 100644 (file)
@@ -29,6 +29,8 @@
                         <type xmlns:operational-dom-store-spi="urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:operational-dom-store">operational-dom-store-spi:operational-dom-datastore</type>
                         <name>distributed-operational-store-service</name>
                     </operational-data-store>
+                    
+                    <allow-concurrent-commits>true</allow-concurrent-commits>
                 </module>
 
                 <module>
index 1595288608cfdbcd5166ccc8f780c1cb98a8e837..3fa8d4e5e9ad48c57b3e811188d916c33e5c5f5f 100644 (file)
@@ -119,7 +119,7 @@ public class DataNormalizerTest {
 
     static final Short OUTER_LIST_ID = (short) 10;
 
-    static final YangInstanceIdentifier OUTER_LIST_PATH_LEGACY = YangInstanceIdentifier.builder(TEST_QNAME)
+    static final YangInstanceIdentifier OUTER_LIST_PATH_LEGACY = YangInstanceIdentifier.builder(TEST_PATH)
             .nodeWithKey(OUTER_LIST_QNAME, ID_QNAME, OUTER_LIST_ID).build();
 
     static final YangInstanceIdentifier LEAF_TWO_PATH_LEGACY = YangInstanceIdentifier.builder(OUTER_LIST_PATH_LEGACY)
@@ -295,7 +295,7 @@ public class DataNormalizerTest {
                 .withNodeIdentifier(new NodeIdentifier(TEST_QNAME)).withChild(testAnyXmlNode).build();
 
         DataNormalizer normalizer = new DataNormalizer(createTestContext());
-        Node<?> legacyNode = normalizer.toLegacy(YangInstanceIdentifier.builder(TEST_QNAME).build(), testContainerNode);
+        Node<?> legacyNode = normalizer.toLegacy(YangInstanceIdentifier.builder().node(TEST_QNAME).build(), testContainerNode);
 
         verifyLegacyNode(
                 legacyNode,
@@ -332,7 +332,7 @@ public class DataNormalizerTest {
 
         DataNormalizer normalizer = new DataNormalizer(createTestContext());
 
-        Node<?> legacyNode = normalizer.toLegacy(YangInstanceIdentifier.builder(TEST_QNAME).build(), testContainerNode);
+        Node<?> legacyNode = normalizer.toLegacy(YangInstanceIdentifier.builder().node(TEST_QNAME).build(), testContainerNode);
 
         verifyLegacyNode(
                 legacyNode,
@@ -359,7 +359,7 @@ public class DataNormalizerTest {
 
         DataNormalizer normalizer = new DataNormalizer(createTestContext());
 
-        Node<?> legacyNode = normalizer.toLegacy(YangInstanceIdentifier.builder(TEST_QNAME).build(), testContainerNode);
+        Node<?> legacyNode = normalizer.toLegacy(YangInstanceIdentifier.builder().node(TEST_QNAME).build(), testContainerNode);
 
         verifyLegacyNode(
                 legacyNode,
index 2eac2400b5a39807c9b188b37f0d693c2c827213..58d805b2b50680be8ab1feb6c6d30bb365bfdf64 100644 (file)
@@ -13,4 +13,5 @@ import akka.actor.ActorRef;
 public interface ClusterWrapper {
     void subscribeToMemberEvents(ActorRef actorRef);
     String getCurrentMemberName();
+    String getSelfAddress();
 }
index 8910137ec4583272b55ead555b0ed12e11caa02c..857510ad4b5360ef3870ac16bce00e188cee88a7 100644 (file)
@@ -17,6 +17,7 @@ import com.google.common.base.Preconditions;
 public class ClusterWrapperImpl implements ClusterWrapper {
     private final Cluster cluster;
     private final String currentMemberName;
+    private final String selfAddress;
 
     public ClusterWrapperImpl(ActorSystem actorSystem){
         Preconditions.checkNotNull(actorSystem, "actorSystem should not be null");
@@ -31,6 +32,7 @@ public class ClusterWrapperImpl implements ClusterWrapper {
         );
 
         currentMemberName = (String) cluster.getSelfRoles().toArray()[0];
+        selfAddress = cluster.selfAddress().toString();
 
     }
 
@@ -45,4 +47,8 @@ public class ClusterWrapperImpl implements ClusterWrapper {
     public String getCurrentMemberName() {
         return currentMemberName;
     }
+
+    public String getSelfAddress() {
+        return selfAddress;
+    }
 }
index f1c0df4c3ad2a336a6aa8edc7282aa399f160c13..a498826e98977d8b3fba89348e3284f0a4781ef3 100644 (file)
@@ -10,10 +10,8 @@ package org.opendaylight.controller.cluster.datastore;
 
 import akka.actor.Props;
 import akka.japi.Creator;
-
 import com.google.common.base.Preconditions;
 import org.opendaylight.controller.cluster.common.actor.AbstractUntypedActor;
-
 import org.opendaylight.controller.cluster.datastore.messages.DataChanged;
 import org.opendaylight.controller.cluster.datastore.messages.DataChangedReply;
 import org.opendaylight.controller.cluster.datastore.messages.EnableNotification;
@@ -24,7 +22,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 
 public class DataChangeListener extends AbstractUntypedActor {
     private final AsyncDataChangeListener<YangInstanceIdentifier, NormalizedNode<?, ?>> listener;
-    private volatile boolean notificationsEnabled = false;
+    private boolean notificationsEnabled = false;
 
     public DataChangeListener(AsyncDataChangeListener<YangInstanceIdentifier,
                                                       NormalizedNode<?, ?>> listener) {
@@ -55,7 +53,9 @@ public class DataChangeListener extends AbstractUntypedActor {
             change = reply.getChange();
         this.listener.onDataChanged(change);
 
-        if(getSender() != null){
+        // It seems the sender is never null but it doesn't hurt to check. If the caller passes in
+        // a null sender (ActorRef.noSender()), akka translates that to the deadLetters actor.
+        if(getSender() != null && !getContext().system().deadLetters().equals(getSender())) {
             getSender().tell(new DataChangedReply(), getSelf());
         }
     }
index a1b6b9252eb452082f101fe1bb748fb2d6b28536..1a0ee8c2fa6866dfdab97cfeab7087ce37d52ca6 100644 (file)
@@ -8,10 +8,9 @@
 
 package org.opendaylight.controller.cluster.datastore;
 
+import akka.actor.ActorRef;
 import akka.actor.ActorSelection;
-
 import com.google.common.base.Preconditions;
-
 import org.opendaylight.controller.cluster.datastore.messages.DataChanged;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
@@ -33,6 +32,6 @@ public class DataChangeListenerProxy implements AsyncDataChangeListener<YangInst
 
     @Override public void onDataChanged(
         AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> change) {
-        dataChangeListenerActor.tell(new DataChanged(schemaContext, change), null);
+        dataChangeListenerActor.tell(new DataChanged(schemaContext, change), ActorRef.noSender());
     }
 }
index 83164b07d9431a70ce609139a476190a5488ab9a..722e23046e43f4c09d68150a2adc126de81de1bc 100644 (file)
@@ -11,10 +11,8 @@ package org.opendaylight.controller.cluster.datastore;
 import org.opendaylight.controller.cluster.raft.ConfigParams;
 import org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl;
 import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStoreConfigProperties;
-
 import scala.concurrent.duration.Duration;
 import scala.concurrent.duration.FiniteDuration;
-
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -29,29 +27,24 @@ public class DatastoreContext {
     private final int operationTimeoutInSeconds;
     private final String dataStoreMXBeanType;
     private final ConfigParams shardRaftConfig;
+    private final int shardTransactionCommitTimeoutInSeconds;
+    private final int shardTransactionCommitQueueCapacity;
 
-    public DatastoreContext() {
-        this("DistributedDatastore", null, Duration.create(10, TimeUnit.MINUTES), 5, 1000, 20000, 500);
-    }
-
-    public DatastoreContext(String dataStoreMXBeanType,
-            InMemoryDOMDataStoreConfigProperties dataStoreProperties,
-            Duration shardTransactionIdleTimeout,
-            int operationTimeoutInSeconds,
-            int shardJournalRecoveryLogBatchSize,
-            int shardSnapshotBatchCount,
-            int shardHeartbeatIntervalInMillis) {
-        this.dataStoreMXBeanType = dataStoreMXBeanType;
+    private DatastoreContext(InMemoryDOMDataStoreConfigProperties dataStoreProperties,
+            ConfigParams shardRaftConfig, String dataStoreMXBeanType, int operationTimeoutInSeconds,
+            Duration shardTransactionIdleTimeout, int shardTransactionCommitTimeoutInSeconds,
+            int shardTransactionCommitQueueCapacity) {
         this.dataStoreProperties = dataStoreProperties;
-        this.shardTransactionIdleTimeout = shardTransactionIdleTimeout;
+        this.shardRaftConfig = shardRaftConfig;
+        this.dataStoreMXBeanType = dataStoreMXBeanType;
         this.operationTimeoutInSeconds = operationTimeoutInSeconds;
+        this.shardTransactionIdleTimeout = shardTransactionIdleTimeout;
+        this.shardTransactionCommitTimeoutInSeconds = shardTransactionCommitTimeoutInSeconds;
+        this.shardTransactionCommitQueueCapacity = shardTransactionCommitQueueCapacity;
+    }
 
-        DefaultConfigParamsImpl raftConfig = new DefaultConfigParamsImpl();
-        raftConfig.setHeartBeatInterval(new FiniteDuration(shardHeartbeatIntervalInMillis,
-                TimeUnit.MILLISECONDS));
-        raftConfig.setJournalRecoveryLogBatchSize(shardJournalRecoveryLogBatchSize);
-        raftConfig.setSnapshotBatchCount(shardSnapshotBatchCount);
-        shardRaftConfig = raftConfig;
+    public static Builder newBuilder() {
+        return new Builder();
     }
 
     public InMemoryDOMDataStoreConfigProperties getDataStoreProperties() {
@@ -73,4 +66,81 @@ public class DatastoreContext {
     public ConfigParams getShardRaftConfig() {
         return shardRaftConfig;
     }
+
+    public int getShardTransactionCommitTimeoutInSeconds() {
+        return shardTransactionCommitTimeoutInSeconds;
+    }
+
+    public int getShardTransactionCommitQueueCapacity() {
+        return shardTransactionCommitQueueCapacity;
+    }
+
+    public static class Builder {
+        private InMemoryDOMDataStoreConfigProperties dataStoreProperties;
+        private Duration shardTransactionIdleTimeout = Duration.create(10, TimeUnit.MINUTES);
+        private int operationTimeoutInSeconds = 5;
+        private String dataStoreMXBeanType;
+        private int shardTransactionCommitTimeoutInSeconds = 30;
+        private int shardJournalRecoveryLogBatchSize = 1000;
+        private int shardSnapshotBatchCount = 20000;
+        private int shardHeartbeatIntervalInMillis = 500;
+        private int shardTransactionCommitQueueCapacity = 20000;
+
+        public Builder shardTransactionIdleTimeout(Duration shardTransactionIdleTimeout) {
+            this.shardTransactionIdleTimeout = shardTransactionIdleTimeout;
+            return this;
+        }
+
+        public Builder operationTimeoutInSeconds(int operationTimeoutInSeconds) {
+            this.operationTimeoutInSeconds = operationTimeoutInSeconds;
+            return this;
+        }
+
+        public Builder dataStoreMXBeanType(String dataStoreMXBeanType) {
+            this.dataStoreMXBeanType = dataStoreMXBeanType;
+            return this;
+        }
+
+        public Builder dataStoreProperties(InMemoryDOMDataStoreConfigProperties dataStoreProperties) {
+            this.dataStoreProperties = dataStoreProperties;
+            return this;
+        }
+
+        public Builder shardTransactionCommitTimeoutInSeconds(int shardTransactionCommitTimeoutInSeconds) {
+            this.shardTransactionCommitTimeoutInSeconds = shardTransactionCommitTimeoutInSeconds;
+            return this;
+        }
+
+        public Builder shardJournalRecoveryLogBatchSize(int shardJournalRecoveryLogBatchSize) {
+            this.shardJournalRecoveryLogBatchSize = shardJournalRecoveryLogBatchSize;
+            return this;
+        }
+
+        public Builder shardSnapshotBatchCount(int shardSnapshotBatchCount) {
+            this.shardSnapshotBatchCount = shardSnapshotBatchCount;
+            return this;
+        }
+
+        public Builder shardHeartbeatIntervalInMillis(int shardHeartbeatIntervalInMillis) {
+            this.shardHeartbeatIntervalInMillis = shardHeartbeatIntervalInMillis;
+            return this;
+        }
+
+        public Builder shardTransactionCommitQueueCapacity(int shardTransactionCommitQueueCapacity) {
+            this.shardTransactionCommitQueueCapacity = shardTransactionCommitQueueCapacity;
+            return this;
+        }
+
+        public DatastoreContext build() {
+            DefaultConfigParamsImpl raftConfig = new DefaultConfigParamsImpl();
+            raftConfig.setHeartBeatInterval(new FiniteDuration(shardHeartbeatIntervalInMillis,
+                    TimeUnit.MILLISECONDS));
+            raftConfig.setJournalRecoveryLogBatchSize(shardJournalRecoveryLogBatchSize);
+            raftConfig.setSnapshotBatchCount(shardSnapshotBatchCount);
+
+            return new DatastoreContext(dataStoreProperties, raftConfig, dataStoreMXBeanType,
+                    operationTimeoutInSeconds, shardTransactionIdleTimeout,
+                    shardTransactionCommitTimeoutInSeconds, shardTransactionCommitQueueCapacity);
+        }
+    }
 }
index c780881a2ffad1ed50695b7a38111068ec2f8e3f..f6c31aab04c76a376e18dad96dae95aa9cffb637 100644 (file)
@@ -12,6 +12,8 @@ import akka.actor.ActorRef;
 import akka.actor.ActorSystem;
 import akka.dispatch.OnComplete;
 import akka.util.Timeout;
+import com.google.common.base.Optional;
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 import org.opendaylight.controller.cluster.datastore.identifiers.ShardManagerIdentifier;
 import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListener;
@@ -76,44 +78,44 @@ public class DistributedDataStore implements DOMStore, SchemaContextListener, Au
 
         Preconditions.checkNotNull(path, "path should not be null");
         Preconditions.checkNotNull(listener, "listener should not be null");
-        if(LOG.isDebugEnabled()) {
-            LOG.debug("Registering listener: {} for path: {} scope: {}", listener, path, scope);
-        }
-        ActorRef dataChangeListenerActor = actorContext.getActorSystem().actorOf(
-            DataChangeListener.props(listener ));
+
+        LOG.debug("Registering listener: {} for path: {} scope: {}", listener, path, scope);
 
         String shardName = ShardStrategyFactory.getStrategy(path).findShard(path);
 
-        Future future = actorContext.executeLocalShardOperationAsync(shardName,
-            new RegisterChangeListener(path, dataChangeListenerActor.path(), scope),
-            new Timeout(actorContext.getOperationDuration().$times(
-                REGISTER_DATA_CHANGE_LISTENER_TIMEOUT_FACTOR)));
+        Optional<ActorRef> shard = actorContext.findLocalShard(shardName);
+
+        //if shard is NOT local
+        if (!shard.isPresent()) {
+            LOG.debug("No local shard for shardName {} was found so returning a noop registration", shardName);
+            return new NoOpDataChangeListenerRegistration(listener);
+        }
+        //if shard is local
+        ActorRef dataChangeListenerActor = actorContext.getActorSystem().actorOf(DataChangeListener.props(listener));
+        Future future = actorContext.executeOperationAsync(shard.get(),
+                new RegisterChangeListener(path, dataChangeListenerActor.path(), scope),
+                new Timeout(actorContext.getOperationDuration().$times(REGISTER_DATA_CHANGE_LISTENER_TIMEOUT_FACTOR)));
 
-        if (future != null) {
-            final DataChangeListenerRegistrationProxy listenerRegistrationProxy =
+        final DataChangeListenerRegistrationProxy listenerRegistrationProxy =
                 new DataChangeListenerRegistrationProxy(listener, dataChangeListenerActor);
 
-            future.onComplete(new OnComplete(){
+        future.onComplete(new OnComplete() {
 
-                @Override public void onComplete(Throwable failure, Object result)
+            @Override
+            public void onComplete(Throwable failure, Object result)
                     throws Throwable {
-                    if(failure != null){
-                        LOG.error("Failed to register listener at path " + path.toString(), failure);
-                        return;
-                    }
-                    RegisterChangeListenerReply reply = (RegisterChangeListenerReply) result;
-                    listenerRegistrationProxy.setListenerRegistrationActor(actorContext
-                        .actorSelection(reply.getListenerRegistrationPath()));
+                if (failure != null) {
+                    LOG.error("Failed to register listener at path " + path.toString(), failure);
+                    return;
                 }
-            }, actorContext.getActorSystem().dispatcher());
-            return listenerRegistrationProxy;
-        }
-        if(LOG.isDebugEnabled()) {
-            LOG.debug(
-                "No local shard for shardName {} was found so returning a noop registration",
-                shardName);
-        }
-        return new NoOpDataChangeListenerRegistration(listener);
+                RegisterChangeListenerReply reply = (RegisterChangeListenerReply) result;
+                listenerRegistrationProxy.setListenerRegistrationActor(actorContext
+                        .actorSelection(reply.getListenerRegistrationPath()));
+            }
+        }, actorContext.getActorSystem().dispatcher());
+
+        return listenerRegistrationProxy;
+
     }
 
     @Override
@@ -145,4 +147,9 @@ public class DistributedDataStore implements DOMStore, SchemaContextListener, Au
     public void close() throws Exception {
         actorContext.shutdown();
     }
+
+    @VisibleForTesting
+    ActorContext getActorContext() {
+        return actorContext;
+    }
 }
index a3109b66b1116853ebb6977c99f72527468fea44..d0bb3d3b69824d18b2acdb08a4defb50d31953b2 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.controller.cluster.datastore;
 
 import akka.actor.ActorRef;
 import akka.actor.ActorSelection;
+import akka.actor.Cancellable;
 import akka.actor.PoisonPill;
 import akka.actor.Props;
 import akka.event.Logging;
@@ -21,7 +22,6 @@ import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
-import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
@@ -29,19 +29,26 @@ import com.google.protobuf.ByteString;
 import com.google.protobuf.InvalidProtocolBufferException;
 import org.opendaylight.controller.cluster.common.actor.CommonConfig;
 import org.opendaylight.controller.cluster.common.actor.MeteringBehavior;
+import org.opendaylight.controller.cluster.datastore.ShardCommitCoordinator.CohortEntry;
 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;
 import org.opendaylight.controller.cluster.datastore.jmx.mbeans.shard.ShardStats;
+import org.opendaylight.controller.cluster.datastore.messages.AbortTransaction;
+import org.opendaylight.controller.cluster.datastore.messages.AbortTransactionReply;
+import org.opendaylight.controller.cluster.datastore.messages.ActorInitialized;
+import org.opendaylight.controller.cluster.datastore.messages.CanCommitTransaction;
 import org.opendaylight.controller.cluster.datastore.messages.CloseTransactionChain;
+import org.opendaylight.controller.cluster.datastore.messages.CommitTransaction;
 import org.opendaylight.controller.cluster.datastore.messages.CommitTransactionReply;
 import org.opendaylight.controller.cluster.datastore.messages.CreateTransaction;
 import org.opendaylight.controller.cluster.datastore.messages.CreateTransactionReply;
 import org.opendaylight.controller.cluster.datastore.messages.EnableNotification;
-import org.opendaylight.controller.cluster.datastore.messages.ForwardedCommitTransaction;
+import org.opendaylight.controller.cluster.datastore.messages.ForwardedReadyTransaction;
 import org.opendaylight.controller.cluster.datastore.messages.PeerAddressResolved;
 import org.opendaylight.controller.cluster.datastore.messages.ReadData;
 import org.opendaylight.controller.cluster.datastore.messages.ReadDataReply;
+import org.opendaylight.controller.cluster.datastore.messages.ReadyTransactionReply;
 import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListener;
 import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListenerReply;
 import org.opendaylight.controller.cluster.datastore.messages.UpdateSchemaContext;
@@ -54,11 +61,9 @@ import org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshotRep
 import org.opendaylight.controller.cluster.raft.protobuff.client.messages.CompositeModificationPayload;
 import org.opendaylight.controller.cluster.raft.protobuff.client.messages.Payload;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
-import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore;
 import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStoreFactory;
 import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages;
-import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionFactory;
@@ -67,12 +72,17 @@ import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import scala.concurrent.duration.Duration;
+import scala.concurrent.duration.FiniteDuration;
+
+import javax.annotation.Nonnull;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
 
 /**
  * A Shard represents a portion of the logical data tree <br/>
@@ -82,14 +92,15 @@ import java.util.concurrent.ExecutionException;
  */
 public class Shard extends RaftActor {
 
+    private static final Object COMMIT_TRANSACTION_REPLY = new CommitTransactionReply().toSerializable();
+
+    private static final Object TX_COMMIT_TIMEOUT_CHECK_MESSAGE = "txCommitTimeoutCheck";
+
     public static final String DEFAULT_NAME = "default";
 
     // The state of this Shard
     private final InMemoryDOMDataStore store;
 
-    private final Map<Object, DOMStoreThreePhaseCommitCohort>
-        modificationToCohort = new HashMap<>();
-
     private final LoggingAdapter LOG =
         Logging.getLogger(getContext().system(), this);
 
@@ -110,6 +121,14 @@ public class Shard extends RaftActor {
 
     private ActorRef createSnapshotTransaction;
 
+    private int createSnapshotTransactionCounter;
+
+    private final ShardCommitCoordinator commitCoordinator;
+
+    private final long transactionCommitTimeout;
+
+    private Cancellable txCommitTimeoutCheckSchedule;
+
     /**
      * Coordinates persistence recovery on startup.
      */
@@ -148,6 +167,12 @@ public class Shard extends RaftActor {
         if (isMetricsCaptureEnabled()) {
             getContext().become(new MeteringBehavior(this));
         }
+
+        commitCoordinator = new ShardCommitCoordinator(TimeUnit.SECONDS.convert(1, TimeUnit.MINUTES),
+                datastoreContext.getShardTransactionCommitQueueCapacity());
+
+        transactionCommitTimeout = TimeUnit.MILLISECONDS.convert(
+                datastoreContext.getShardTransactionCommitTimeoutInSeconds(), TimeUnit.SECONDS);
     }
 
     private static Map<String, String> mapPeerAddresses(
@@ -173,7 +198,17 @@ public class Shard extends RaftActor {
         return Props.create(new ShardCreator(name, peerAddresses, datastoreContext, schemaContext));
     }
 
-    @Override public void onReceiveRecover(Object message) {
+    @Override
+    public void postStop() {
+        super.postStop();
+
+        if(txCommitTimeoutCheckSchedule != null) {
+            txCommitTimeoutCheckSchedule.cancel();
+        }
+    }
+
+    @Override
+    public void onReceiveRecover(Object message) {
         if(LOG.isDebugEnabled()) {
             LOG.debug("onReceiveRecover: Received message {} from {}",
                 message.getClass().toString(),
@@ -187,52 +222,241 @@ public class Shard extends RaftActor {
         }
     }
 
-    @Override public void onReceiveCommand(Object message) {
+    @Override
+    public void onReceiveCommand(Object message) {
         if(LOG.isDebugEnabled()) {
-            LOG.debug("onReceiveCommand: Received message {} from {}",
-                message.getClass().toString(),
-                getSender());
+            LOG.debug("onReceiveCommand: Received message {} from {}", message, getSender());
         }
 
         if(message.getClass().equals(ReadDataReply.SERIALIZABLE_CLASS)) {
-            // This must be for install snapshot. Don't want to open this up and trigger
-            // deSerialization
-            self()
-                .tell(new CaptureSnapshotReply(ReadDataReply.getNormalizedNodeByteString(message)),
-                    self());
-
-            createSnapshotTransaction = null;
-            // Send a PoisonPill instead of sending close transaction because we do not really need
-            // a response
-            getSender().tell(PoisonPill.getInstance(), self());
-
+            handleReadDataReply(message);
+        } else if (message.getClass().equals(CreateTransaction.SERIALIZABLE_CLASS)) {
+            handleCreateTransaction(message);
+        } else if(message instanceof ForwardedReadyTransaction) {
+            handleForwardedReadyTransaction((ForwardedReadyTransaction)message);
+        } else if(message.getClass().equals(CanCommitTransaction.SERIALIZABLE_CLASS)) {
+            handleCanCommitTransaction(CanCommitTransaction.fromSerializable(message));
+        } else if(message.getClass().equals(CommitTransaction.SERIALIZABLE_CLASS)) {
+            handleCommitTransaction(CommitTransaction.fromSerializable(message));
+        } else if(message.getClass().equals(AbortTransaction.SERIALIZABLE_CLASS)) {
+            handleAbortTransaction(AbortTransaction.fromSerializable(message));
         } else if (message.getClass().equals(CloseTransactionChain.SERIALIZABLE_CLASS)){
             closeTransactionChain(CloseTransactionChain.fromSerializable(message));
         } else if (message instanceof RegisterChangeListener) {
             registerChangeListener((RegisterChangeListener) message);
         } else if (message instanceof UpdateSchemaContext) {
             updateSchemaContext((UpdateSchemaContext) message);
-        } else if (message instanceof ForwardedCommitTransaction) {
-            handleForwardedCommit((ForwardedCommitTransaction) message);
-        } else if (message.getClass()
-            .equals(CreateTransaction.SERIALIZABLE_CLASS)) {
-            if (isLeader()) {
-                createTransaction(CreateTransaction.fromSerializable(message));
-            } else if (getLeader() != null) {
-                getLeader().forward(message, getContext());
-            } else {
-                getSender().tell(new akka.actor.Status.Failure(new IllegalStateException(
-                    "Could not find leader so transaction cannot be created")), getSelf());
-            }
         } else if (message instanceof PeerAddressResolved) {
             PeerAddressResolved resolved = (PeerAddressResolved) message;
             setPeerAddress(resolved.getPeerId().toString(),
                 resolved.getPeerAddress());
+        } else if(message.equals(TX_COMMIT_TIMEOUT_CHECK_MESSAGE)) {
+            handleTransactionCommitTimeoutCheck();
         } else {
             super.onReceiveCommand(message);
         }
     }
 
+    private void handleTransactionCommitTimeoutCheck() {
+        CohortEntry cohortEntry = commitCoordinator.getCurrentCohortEntry();
+        if(cohortEntry != null) {
+            long elapsed = System.currentTimeMillis() - cohortEntry.getLastAccessTime();
+            if(elapsed > transactionCommitTimeout) {
+                LOG.warning("Current transaction {} has timed out after {} ms - aborting",
+                        cohortEntry.getTransactionID(), transactionCommitTimeout);
+
+                doAbortTransaction(cohortEntry.getTransactionID(), null);
+            }
+        }
+    }
+
+    private void handleCommitTransaction(CommitTransaction commit) {
+        final String transactionID = commit.getTransactionID();
+
+        LOG.debug("Committing transaction {}", transactionID);
+
+        // Get the current in-progress cohort entry in the commitCoordinator if it corresponds to
+        // this transaction.
+        final CohortEntry cohortEntry = commitCoordinator.getCohortEntryIfCurrent(transactionID);
+        if(cohortEntry == null) {
+            // We're not the current Tx - the Tx was likely expired b/c it took too long in
+            // between the canCommit and commit messages.
+            IllegalStateException ex = new IllegalStateException(
+                    String.format("Cannot commit transaction %s - it is not the current transaction",
+                            transactionID));
+            LOG.error(ex.getMessage());
+            shardMBean.incrementFailedTransactionsCount();
+            getSender().tell(new akka.actor.Status.Failure(ex), getSelf());
+            return;
+        }
+
+        // We perform the preCommit phase here atomically with the commit phase. This is an
+        // optimization to eliminate the overhead of an extra preCommit message. We lose front-end
+        // coordination of preCommit across shards in case of failure but preCommit should not
+        // normally fail since we ensure only one concurrent 3-phase commit.
+
+        try {
+            // We block on the future here so we don't have to worry about possibly accessing our
+            // state on a different thread outside of our dispatcher. Also, the data store
+            // currently uses a same thread executor anyway.
+            cohortEntry.getCohort().preCommit().get();
+
+            if(persistent) {
+                Shard.this.persistData(getSender(), transactionID,
+                        new CompositeModificationPayload(cohortEntry.getModification().toSerializable()));
+            } else {
+                Shard.this.finishCommit(getSender(), transactionID);
+            }
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error(e, "An exception occurred while preCommitting transaction {}",
+                    cohortEntry.getTransactionID());
+            shardMBean.incrementFailedTransactionsCount();
+            getSender().tell(new akka.actor.Status.Failure(e), getSelf());
+        }
+
+        cohortEntry.updateLastAccessTime();
+    }
+
+    private void finishCommit(@Nonnull final ActorRef sender, final @Nonnull String transactionID) {
+        // With persistence enabled, this method is called via applyState by the leader strategy
+        // after the commit has been replicated to a majority of the followers.
+
+        CohortEntry cohortEntry = commitCoordinator.getCohortEntryIfCurrent(transactionID);
+        if(cohortEntry == null) {
+            // The transaction is no longer the current commit. This can happen if the transaction
+            // was aborted prior, most likely due to timeout in the front-end. We need to finish
+            // committing the transaction though since it was successfully persisted and replicated
+            // however we can't use the original cohort b/c it was already preCommitted and may
+            // conflict with the current commit or may have been aborted so we commit with a new
+            // transaction.
+            cohortEntry = commitCoordinator.getAndRemoveCohortEntry(transactionID);
+            if(cohortEntry != null) {
+                commitWithNewTransaction(cohortEntry.getModification());
+                sender.tell(COMMIT_TRANSACTION_REPLY, getSelf());
+            } else {
+                // This really shouldn't happen - it likely means that persistence or replication
+                // took so long to complete such that the cohort entry was expired from the cache.
+                IllegalStateException ex = new IllegalStateException(
+                        String.format("Could not finish committing transaction %s - no CohortEntry found",
+                                transactionID));
+                LOG.error(ex.getMessage());
+                sender.tell(new akka.actor.Status.Failure(ex), getSelf());
+            }
+
+            return;
+        }
+
+        LOG.debug("Finishing commit for transaction {}", cohortEntry.getTransactionID());
+
+        try {
+            // We block on the future here so we don't have to worry about possibly accessing our
+            // state on a different thread outside of our dispatcher. Also, the data store
+            // currently uses a same thread executor anyway.
+            cohortEntry.getCohort().commit().get();
+
+            sender.tell(COMMIT_TRANSACTION_REPLY, getSelf());
+
+            shardMBean.incrementCommittedTransactionCount();
+            shardMBean.setLastCommittedTransactionTime(System.currentTimeMillis());
+
+        } catch (InterruptedException | ExecutionException e) {
+            sender.tell(new akka.actor.Status.Failure(e), getSelf());
+
+            LOG.error(e, "An exception occurred while committing transaction {}", transactionID);
+            shardMBean.incrementFailedTransactionsCount();
+        }
+
+        commitCoordinator.currentTransactionComplete(transactionID, true);
+    }
+
+    private void handleCanCommitTransaction(CanCommitTransaction canCommit) {
+        LOG.debug("Can committing transaction {}", canCommit.getTransactionID());
+        commitCoordinator.handleCanCommit(canCommit, getSender(), self());
+    }
+
+    private void handleForwardedReadyTransaction(ForwardedReadyTransaction ready) {
+        LOG.debug("Readying transaction {}", ready.getTransactionID());
+
+        // This message is forwarded by the ShardTransaction on ready. We cache the cohort in the
+        // commitCoordinator in preparation for the subsequent three phase commit initiated by
+        // the front-end.
+        commitCoordinator.transactionReady(ready.getTransactionID(), ready.getCohort(),
+                ready.getModification());
+
+        // Return our actor path as we'll handle the three phase commit.
+        ReadyTransactionReply readyTransactionReply =
+            new ReadyTransactionReply(Serialization.serializedActorPath(self()));
+        getSender().tell(
+            ready.isReturnSerialized() ? readyTransactionReply.toSerializable() : readyTransactionReply,
+            getSelf());
+    }
+
+    private void handleAbortTransaction(AbortTransaction abort) {
+        doAbortTransaction(abort.getTransactionID(), getSender());
+    }
+
+    private void doAbortTransaction(String transactionID, final ActorRef sender) {
+        final CohortEntry cohortEntry = commitCoordinator.getCohortEntryIfCurrent(transactionID);
+        if(cohortEntry != null) {
+            LOG.debug("Aborting transaction {}", transactionID);
+
+            // We don't remove the cached cohort entry here (ie pass false) in case the Tx was
+            // aborted during replication in which case we may still commit locally if replication
+            // succeeds.
+            commitCoordinator.currentTransactionComplete(transactionID, false);
+
+            final ListenableFuture<Void> future = cohortEntry.getCohort().abort();
+            final ActorRef self = getSelf();
+
+            Futures.addCallback(future, new FutureCallback<Void>() {
+                @Override
+                public void onSuccess(Void v) {
+                    shardMBean.incrementAbortTransactionsCount();
+
+                    if(sender != null) {
+                        sender.tell(new AbortTransactionReply().toSerializable(), self);
+                    }
+                }
+
+                @Override
+                public void onFailure(Throwable t) {
+                    LOG.error(t, "An exception happened during abort");
+
+                    if(sender != null) {
+                        sender.tell(new akka.actor.Status.Failure(t), self);
+                    }
+                }
+            });
+        }
+    }
+
+    private void handleCreateTransaction(Object message) {
+        if (isLeader()) {
+            createTransaction(CreateTransaction.fromSerializable(message));
+        } else if (getLeader() != null) {
+            getLeader().forward(message, getContext());
+        } else {
+            getSender().tell(new akka.actor.Status.Failure(new IllegalStateException(
+                "Could not find shard leader so transaction cannot be created. This typically happens" +
+                " when system is coming up or recovering and a leader is being elected. Try again" +
+                " later.")), getSelf());
+        }
+    }
+
+    private void handleReadDataReply(Object message) {
+        // This must be for install snapshot. Don't want to open this up and trigger
+        // deSerialization
+
+        self().tell(new CaptureSnapshotReply(ReadDataReply.getNormalizedNodeByteString(message)),
+                self());
+
+        createSnapshotTransaction = null;
+
+        // Send a PoisonPill instead of sending close transaction because we do not really need
+        // a response
+        getSender().tell(PoisonPill.getInstance(), self());
+    }
+
     private void closeTransactionChain(CloseTransactionChain closeTransactionChain) {
         DOMStoreTransactionChain chain =
             transactionChains.remove(closeTransactionChain.getTransactionChainId());
@@ -262,33 +486,33 @@ public class Shard extends RaftActor {
             throw new NullPointerException("schemaContext should not be null");
         }
 
-        if (transactionType
-            == TransactionProxy.TransactionType.READ_ONLY.ordinal()) {
+        if (transactionType == TransactionProxy.TransactionType.READ_ONLY.ordinal()) {
 
             shardMBean.incrementReadOnlyTransactionCount();
 
             return getContext().actorOf(
                 ShardTransaction.props(factory.newReadOnlyTransaction(), getSelf(),
-                        schemaContext,datastoreContext, shardMBean), transactionId.toString());
+                        schemaContext,datastoreContext, shardMBean,
+                        transactionId.getRemoteTransactionId()), transactionId.toString());
 
-        } else if (transactionType
-            == TransactionProxy.TransactionType.READ_WRITE.ordinal()) {
+        } else if (transactionType == TransactionProxy.TransactionType.READ_WRITE.ordinal()) {
 
             shardMBean.incrementReadWriteTransactionCount();
 
             return getContext().actorOf(
                 ShardTransaction.props(factory.newReadWriteTransaction(), getSelf(),
-                        schemaContext, datastoreContext, shardMBean), transactionId.toString());
+                        schemaContext, datastoreContext, shardMBean,
+                        transactionId.getRemoteTransactionId()), transactionId.toString());
 
 
-        } else if (transactionType
-            == TransactionProxy.TransactionType.WRITE_ONLY.ordinal()) {
+        } else if (transactionType == TransactionProxy.TransactionType.WRITE_ONLY.ordinal()) {
 
             shardMBean.incrementWriteOnlyTransactionCount();
 
             return getContext().actorOf(
                 ShardTransaction.props(factory.newWriteOnlyTransaction(), getSelf(),
-                        schemaContext, datastoreContext, shardMBean), transactionId.toString());
+                        schemaContext, datastoreContext, shardMBean,
+                        transactionId.getRemoteTransactionId()), transactionId.toString());
         } else {
             throw new IllegalArgumentException(
                 "Shard="+name + ":CreateTransaction message has unidentified transaction type="
@@ -329,70 +553,19 @@ public class Shard extends RaftActor {
         commitCohort.commit().get();
     }
 
-
-    private void commit(final ActorRef sender, Object serialized) {
-        Modification modification = MutableCompositeModification
-            .fromSerializable(serialized, schemaContext);
-        DOMStoreThreePhaseCommitCohort cohort =
-            modificationToCohort.remove(serialized);
-        if (cohort == null) {
-            // If there's no cached cohort then we must be applying replicated state.
-            commitWithNewTransaction(serialized);
-            return;
-        }
-
-        if(sender == null) {
-            LOG.error("Commit failed. Sender cannot be null");
-            return;
-        }
-
-        ListenableFuture<Void> future = cohort.commit();
-
-        Futures.addCallback(future, new FutureCallback<Void>() {
-            @Override
-            public void onSuccess(Void v) {
-                sender.tell(new CommitTransactionReply().toSerializable(), getSelf());
-                shardMBean.incrementCommittedTransactionCount();
-                shardMBean.setLastCommittedTransactionTime(System.currentTimeMillis());
-            }
-
-            @Override
-            public void onFailure(Throwable t) {
-                LOG.error(t, "An exception happened during commit");
-                shardMBean.incrementFailedTransactionsCount();
-                sender.tell(new akka.actor.Status.Failure(t), getSelf());
-            }
-        });
-
-    }
-
-    private void commitWithNewTransaction(Object modification) {
+    private void commitWithNewTransaction(Modification modification) {
         DOMStoreWriteTransaction tx = store.newWriteOnlyTransaction();
-        MutableCompositeModification.fromSerializable(modification, schemaContext).apply(tx);
+        modification.apply(tx);
         try {
             syncCommitTransaction(tx);
             shardMBean.incrementCommittedTransactionCount();
+            shardMBean.setLastCommittedTransactionTime(System.currentTimeMillis());
         } catch (InterruptedException | ExecutionException e) {
             shardMBean.incrementFailedTransactionsCount();
             LOG.error(e, "Failed to commit");
         }
     }
 
-    private void handleForwardedCommit(ForwardedCommitTransaction message) {
-        Object serializedModification =
-            message.getModification().toSerializable();
-
-        modificationToCohort
-            .put(serializedModification, message.getCohort());
-
-        if (persistent) {
-            this.persistData(getSender(), "identifier",
-                new CompositeModificationPayload(serializedModification));
-        } else {
-            this.commit(getSender(), serializedModification);
-        }
-    }
-
     private void updateSchemaContext(UpdateSchemaContext message) {
         this.schemaContext = message.getSchemaContext();
         updateSchemaContext(message.getSchemaContext());
@@ -522,6 +695,16 @@ public class Shard extends RaftActor {
         recoveryCoordinator = null;
         currentLogRecoveryBatch = null;
         updateJournalStats();
+
+        //notify shard manager
+        getContext().parent().tell(new ActorInitialized(), getSelf());
+
+        // Schedule a message to be periodically sent to check if the current in-progress
+        // transaction should be expired and aborted.
+        FiniteDuration period = Duration.create(transactionCommitTimeout / 3, TimeUnit.MILLISECONDS);
+        txCommitTimeoutCheckSchedule = getContext().system().scheduler().schedule(
+                period, period, getSelf(),
+                TX_COMMIT_TIMEOUT_CHECK_MESSAGE, getContext().dispatcher(), ActorRef.noSender());
     }
 
     @Override
@@ -530,14 +713,19 @@ public class Shard extends RaftActor {
         if (data instanceof CompositeModificationPayload) {
             Object modification = ((CompositeModificationPayload) data).getModification();
 
-            if (modification != null) {
-                commit(clientActor, modification);
-            } else {
+            if(modification == null) {
                 LOG.error(
-                    "modification is null - this is very unexpected, clientActor = {}, identifier = {}",
-                    identifier, clientActor != null ? clientActor.path().toString() : null);
+                     "modification is null - this is very unexpected, clientActor = {}, identifier = {}",
+                     identifier, clientActor != null ? clientActor.path().toString() : null);
+            } else if(clientActor == null) {
+                // There's no clientActor to which to send a commit reply so we must be applying
+                // replicated state from the leader.
+                commitWithNewTransaction(MutableCompositeModification.fromSerializable(
+                        modification, schemaContext));
+            } else {
+                // This must be the OK to commit after replication consensus.
+                finishCommit(clientActor, identifier);
             }
-
         } else {
             LOG.error("Unknown state received {} Class loader = {} CompositeNodeMod.ClassLoader = {}",
                     data, data.getClass().getClassLoader(),
@@ -568,7 +756,7 @@ public class Shard extends RaftActor {
             // so that this actor does not get block building the snapshot
             createSnapshotTransaction = createTransaction(
                 TransactionProxy.TransactionType.READ_ONLY.ordinal(),
-                "createSnapshot", "");
+                "createSnapshot" + ++createSnapshotTransactionCounter, "");
 
             createSnapshotTransaction.tell(
                 new ReadData(YangInstanceIdentifier.builder().build()).toSerializable(), self());
@@ -659,29 +847,8 @@ public class Shard extends RaftActor {
     }
 
     @VisibleForTesting
-    NormalizedNode<?,?> readStore(YangInstanceIdentifier id)
-            throws ExecutionException, InterruptedException {
-        DOMStoreReadTransaction transaction = store.newReadOnlyTransaction();
-
-        CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> future =
-            transaction.read(id);
-
-        Optional<NormalizedNode<?, ?>> optional = future.get();
-        NormalizedNode<?, ?> node = optional.isPresent()? optional.get() : null;
-
-        transaction.close();
-
-        return node;
-    }
-
-    @VisibleForTesting
-    void writeToStore(YangInstanceIdentifier id, NormalizedNode<?,?> node)
-        throws ExecutionException, InterruptedException {
-        DOMStoreWriteTransaction transaction = store.newWriteOnlyTransaction();
-
-        transaction.write(id, node);
-
-        syncCommitTransaction(transaction);
+    InMemoryDOMDataStore getDataStore() {
+        return store;
     }
 
     @VisibleForTesting
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardCommitCoordinator.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardCommitCoordinator.java
new file mode 100644 (file)
index 0000000..f3b4e41
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * 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.cluster.datastore;
+
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import org.opendaylight.controller.cluster.datastore.messages.CanCommitTransaction;
+import org.opendaylight.controller.cluster.datastore.messages.CanCommitTransactionReply;
+import org.opendaylight.controller.cluster.datastore.modification.Modification;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import akka.actor.ActorRef;
+import akka.actor.Status;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+
+/**
+ * Coordinates commits for a shard ensuring only one concurrent 3-phase commit.
+ *
+ * @author Thomas Pantelis
+ */
+public class ShardCommitCoordinator {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ShardCommitCoordinator.class);
+
+    private static final Object CAN_COMMIT_REPLY_TRUE =
+            new CanCommitTransactionReply(Boolean.TRUE).toSerializable();
+
+    private static final Object CAN_COMMIT_REPLY_FALSE =
+            new CanCommitTransactionReply(Boolean.FALSE).toSerializable();
+
+    private final Cache<String, CohortEntry> cohortCache;
+
+    private CohortEntry currentCohortEntry;
+
+    private final Queue<CohortEntry> queuedCohortEntries;
+
+    private final int queueCapacity;
+
+    public ShardCommitCoordinator(long cacheExpiryTimeoutInSec, int queueCapacity) {
+        cohortCache = CacheBuilder.newBuilder().expireAfterAccess(
+                cacheExpiryTimeoutInSec, TimeUnit.SECONDS).build();
+
+        this.queueCapacity = queueCapacity;
+
+        // We use a LinkedList here to avoid synchronization overhead with concurrent queue impls
+        // since this should only be accessed on the shard's dispatcher.
+        queuedCohortEntries = new LinkedList<>();
+    }
+
+    /**
+     * This method caches a cohort entry for the given transactions ID in preparation for the
+     * subsequent 3-phase commit.
+     *
+     * @param transactionID the ID of the transaction
+     * @param cohort the cohort to participate in the transaction commit
+     * @param modification the modification made by the transaction
+     */
+    public void transactionReady(String transactionID, DOMStoreThreePhaseCommitCohort cohort,
+            Modification modification) {
+
+        cohortCache.put(transactionID, new CohortEntry(transactionID, cohort, modification));
+    }
+
+    /**
+     * This method handles the canCommit phase for a transaction.
+     *
+     * @param canCommit the CanCommitTransaction message
+     * @param sender the actor that sent the message
+     * @param shard the transaction's shard actor
+     */
+    public void handleCanCommit(CanCommitTransaction canCommit, final ActorRef sender,
+            final ActorRef shard) {
+        String transactionID = canCommit.getTransactionID();
+        if(LOG.isDebugEnabled()) {
+            LOG.debug("Processing canCommit for transaction {} for shard {}",
+                    transactionID, shard.path());
+        }
+
+        // Lookup the cohort entry that was cached previously (or should have been) by
+        // transactionReady (via the ForwardedReadyTransaction message).
+        final CohortEntry cohortEntry = cohortCache.getIfPresent(transactionID);
+        if(cohortEntry == null) {
+            // Either canCommit was invoked before ready(shouldn't happen)  or a long time passed
+            // between canCommit and ready and the entry was expired from the cache.
+            IllegalStateException ex = new IllegalStateException(
+                    String.format("No cohort entry found for transaction %s", transactionID));
+            LOG.error(ex.getMessage());
+            sender.tell(new Status.Failure(ex), shard);
+            return;
+        }
+
+        cohortEntry.setCanCommitSender(sender);
+        cohortEntry.setShard(shard);
+
+        if(currentCohortEntry != null) {
+            // There's already a Tx commit in progress - attempt to queue this entry to be
+            // committed after the current Tx completes.
+            LOG.debug("Transaction {} is already in progress - queueing transaction {}",
+                    currentCohortEntry.getTransactionID(), transactionID);
+
+            if(queuedCohortEntries.size() < queueCapacity) {
+                queuedCohortEntries.offer(cohortEntry);
+            } else {
+                removeCohortEntry(transactionID);
+
+                RuntimeException ex = new RuntimeException(
+                        String.format("Could not enqueue transaction %s - the maximum commit queue"+
+                                      " capacity %d has been reached.",
+                                transactionID, queueCapacity));
+                LOG.error(ex.getMessage());
+                sender.tell(new Status.Failure(ex), shard);
+            }
+        } else {
+            // No Tx commit currently in progress - make this the current entry and proceed with
+            // canCommit.
+            cohortEntry.updateLastAccessTime();
+            currentCohortEntry = cohortEntry;
+
+            doCanCommit(cohortEntry);
+        }
+    }
+
+    private void doCanCommit(final CohortEntry cohortEntry) {
+
+        try {
+            // We block on the future here so we don't have to worry about possibly accessing our
+            // state on a different thread outside of our dispatcher. Also, the data store
+            // currently uses a same thread executor anyway.
+            Boolean canCommit = cohortEntry.getCohort().canCommit().get();
+
+            cohortEntry.getCanCommitSender().tell(
+                    canCommit ? CAN_COMMIT_REPLY_TRUE : CAN_COMMIT_REPLY_FALSE, cohortEntry.getShard());
+
+            if(!canCommit) {
+                // Remove the entry from the cache now since the Tx will be aborted.
+                removeCohortEntry(cohortEntry.getTransactionID());
+            }
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.debug("An exception occurred during canCommit", e);
+
+            // Remove the entry from the cache now since the Tx will be aborted.
+            removeCohortEntry(cohortEntry.getTransactionID());
+            cohortEntry.getCanCommitSender().tell(new Status.Failure(e), cohortEntry.getShard());
+        }
+    }
+
+    /**
+     * Returns the cohort entry for the Tx commit currently in progress if the given transaction ID
+     * matches the current entry.
+     *
+     * @param transactionID the ID of the transaction
+     * @return the current CohortEntry or null if the given transaction ID does not match the
+     *         current entry.
+     */
+    public CohortEntry getCohortEntryIfCurrent(String transactionID) {
+        if(isCurrentTransaction(transactionID)) {
+            return currentCohortEntry;
+        }
+
+        return null;
+    }
+
+    public CohortEntry getCurrentCohortEntry() {
+        return currentCohortEntry;
+    }
+
+    public CohortEntry getAndRemoveCohortEntry(String transactionID) {
+        CohortEntry cohortEntry = cohortCache.getIfPresent(transactionID);
+        cohortCache.invalidate(transactionID);
+        return cohortEntry;
+    }
+
+    public void removeCohortEntry(String transactionID) {
+        cohortCache.invalidate(transactionID);
+    }
+
+    public boolean isCurrentTransaction(String transactionID) {
+        return currentCohortEntry != null &&
+                currentCohortEntry.getTransactionID().equals(transactionID);
+    }
+
+    /**
+     * This method is called when a transaction is complete, successful or not. If the given
+     * given transaction ID matches the current in-progress transaction, the next cohort entry,
+     * if any, is dequeued and processed.
+     *
+     * @param transactionID the ID of the completed transaction
+     * @param removeCohortEntry if true the CohortEntry for the transaction is also removed from
+     *        the cache.
+     */
+    public void currentTransactionComplete(String transactionID, boolean removeCohortEntry) {
+        if(removeCohortEntry) {
+            removeCohortEntry(transactionID);
+        }
+
+        if(isCurrentTransaction(transactionID)) {
+            // Dequeue the next cohort entry waiting in the queue.
+            currentCohortEntry = queuedCohortEntries.poll();
+            if(currentCohortEntry != null) {
+                doCanCommit(currentCohortEntry);
+            }
+        }
+    }
+
+    static class CohortEntry {
+        private final String transactionID;
+        private final DOMStoreThreePhaseCommitCohort cohort;
+        private final Modification modification;
+        private ActorRef canCommitSender;
+        private ActorRef shard;
+        private long lastAccessTime;
+
+        CohortEntry(String transactionID, DOMStoreThreePhaseCommitCohort cohort,
+                Modification modification) {
+            this.transactionID = transactionID;
+            this.cohort = cohort;
+            this.modification = modification;
+        }
+
+        void updateLastAccessTime() {
+            lastAccessTime = System.currentTimeMillis();
+        }
+
+        long getLastAccessTime() {
+            return lastAccessTime;
+        }
+
+        String getTransactionID() {
+            return transactionID;
+        }
+
+        DOMStoreThreePhaseCommitCohort getCohort() {
+            return cohort;
+        }
+
+        Modification getModification() {
+            return modification;
+        }
+
+        ActorRef getCanCommitSender() {
+            return canCommitSender;
+        }
+
+        void setCanCommitSender(ActorRef canCommitSender) {
+            this.canCommitSender = canCommitSender;
+        }
+
+        ActorRef getShard() {
+            return shard;
+        }
+
+        void setShard(ActorRef shard) {
+            this.shard = shard;
+        }
+    }
+}
index a8a182380911db26f8c9530e363441d2d2b491cc..157f1cb3771cd71ddd1ddf14d2541bef3a0aefc3 100644 (file)
@@ -24,11 +24,14 @@ import akka.persistence.RecoveryCompleted;
 import akka.persistence.RecoveryFailure;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
-import org.opendaylight.controller.cluster.common.actor.AbstractUntypedPersistentActor;
+import com.google.common.base.Supplier;
+import org.opendaylight.controller.cluster.common.actor.AbstractUntypedPersistentActorWithMetering;
 import org.opendaylight.controller.cluster.datastore.identifiers.ShardIdentifier;
 import org.opendaylight.controller.cluster.datastore.identifiers.ShardManagerIdentifier;
 import org.opendaylight.controller.cluster.datastore.jmx.mbeans.shardmanager.ShardManagerInfo;
 import org.opendaylight.controller.cluster.datastore.jmx.mbeans.shardmanager.ShardManagerInfoMBean;
+import org.opendaylight.controller.cluster.datastore.messages.ActorInitialized;
+import org.opendaylight.controller.cluster.datastore.messages.ActorNotInitialized;
 import org.opendaylight.controller.cluster.datastore.messages.FindLocalShard;
 import org.opendaylight.controller.cluster.datastore.messages.FindPrimary;
 import org.opendaylight.controller.cluster.datastore.messages.LocalShardFound;
@@ -40,7 +43,6 @@ import org.opendaylight.controller.cluster.datastore.messages.UpdateSchemaContex
 import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import scala.concurrent.duration.Duration;
-
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -59,7 +61,7 @@ import java.util.Set;
  * <li> Monitor the cluster members and store their addresses
  * <ul>
  */
-public class ShardManager extends AbstractUntypedPersistentActor {
+public class ShardManager extends AbstractUntypedPersistentActorWithMetering {
 
     protected final LoggingAdapter LOG =
         Logging.getLogger(getContext().system(), this);
@@ -92,7 +94,7 @@ public class ShardManager extends AbstractUntypedPersistentActor {
      * @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,
+    protected ShardManager(String type, ClusterWrapper cluster, Configuration configuration,
             DatastoreContext datastoreContext) {
 
         this.type = Preconditions.checkNotNull(type, "type should not be null");
@@ -103,7 +105,7 @@ public class ShardManager extends AbstractUntypedPersistentActor {
         // Subscribe this actor to cluster member events
         cluster.subscribeToMemberEvents(getSelf());
 
-        //createLocalShards(null);
+        createLocalShards();
     }
 
     public static Props props(final String type,
@@ -121,12 +123,13 @@ public class ShardManager extends AbstractUntypedPersistentActor {
     @Override
     public void handleCommand(Object message) throws Exception {
         if (message.getClass().equals(FindPrimary.SERIALIZABLE_CLASS)) {
-            findPrimary(
-                FindPrimary.fromSerializable(message));
+            findPrimary(FindPrimary.fromSerializable(message));
         } else if(message instanceof FindLocalShard){
             findLocalShard((FindLocalShard) message);
         } else if (message instanceof UpdateSchemaContext) {
             updateSchemaContext(message);
+        } else if(message instanceof ActorInitialized) {
+            onActorInitialized(message);
         } else if (message instanceof ClusterEvent.MemberUp){
             memberUp((ClusterEvent.MemberUp) message);
         } else if(message instanceof ClusterEvent.MemberRemoved) {
@@ -139,8 +142,33 @@ public class ShardManager extends AbstractUntypedPersistentActor {
 
     }
 
-    @Override protected void handleRecover(Object message) throws Exception {
+    private void onActorInitialized(Object message) {
+        final ActorRef sender = getSender();
+
+        if (sender == null) {
+            return; //why is a non-actor sending this message? Just ignore.
+        }
+
+        String actorName = sender.path().name();
+        //find shard name from actor name; actor name is stringified shardId
+        ShardIdentifier shardId = ShardIdentifier.builder().fromShardIdString(actorName).build();
+
+        if (shardId.getShardName() == null) {
+            return;
+        }
+        markShardAsInitialized(shardId.getShardName());
+    }
+
+    private void markShardAsInitialized(String shardName) {
+        LOG.debug("Initializing shard [{}]", shardName);
+        ShardInformation shardInformation = localShards.get(shardName);
+        if (shardInformation != null) {
+            shardInformation.setShardInitialized(true);
+        }
+    }
 
+    @Override
+    protected void handleRecover(Object message) throws Exception {
         if(message instanceof SchemaContextModules){
             SchemaContextModules msg = (SchemaContextModules) message;
             knownModules.clear();
@@ -157,16 +185,28 @@ public class ShardManager extends AbstractUntypedPersistentActor {
     }
 
     private void findLocalShard(FindLocalShard message) {
-        ShardInformation shardInformation =
-            localShards.get(message.getShardName());
+        final ShardInformation shardInformation = localShards.get(message.getShardName());
 
-        if(shardInformation != null){
-            getSender().tell(new LocalShardFound(shardInformation.getActor()), getSelf());
+        if(shardInformation == null){
+            getSender().tell(new LocalShardNotFound(message.getShardName()), getSelf());
             return;
         }
 
-        getSender().tell(new LocalShardNotFound(message.getShardName()),
-            getSelf());
+        sendResponse(shardInformation, new Supplier<Object>() {
+            @Override
+            public Object get() {
+                return new LocalShardFound(shardInformation.getActor());
+            }
+        });
+    }
+
+    private void sendResponse(ShardInformation shardInformation,  Supplier<Object> messageSupplier) {
+        if (shardInformation.getActor() == null || !shardInformation.isShardInitialized()) {
+            getSender().tell(new ActorNotInitialized(), getSelf());
+            return;
+        }
+
+        getSender().tell(messageSupplier.get(), getSelf());
     }
 
     private void memberRemoved(ClusterEvent.MemberRemoved message) {
@@ -176,7 +216,7 @@ public class ShardManager extends AbstractUntypedPersistentActor {
     private void memberUp(ClusterEvent.MemberUp message) {
         String memberName = message.member().roles().head();
 
-        memberNameToAddress.put(memberName , message.member().address());
+        memberNameToAddress.put(memberName, message.member().address());
 
         for(ShardInformation info : localShards.values()){
             String shardName = info.getShardName();
@@ -210,12 +250,15 @@ public class ShardManager extends AbstractUntypedPersistentActor {
 
             persist(new SchemaContextModules(newModules), new Procedure<SchemaContextModules>() {
 
-                @Override public void apply(SchemaContextModules param) throws Exception {
+                @Override
+                public void apply(SchemaContextModules param) throws Exception {
                     LOG.info("Sending new SchemaContext to Shards");
-                    if (localShards.size() == 0) {
-                        createLocalShards(schemaContext);
-                    } else {
-                        for (ShardInformation info : localShards.values()) {
+                    for (ShardInformation info : localShards.values()) {
+                        if(info.getActor() == null) {
+                            info.setActor(getContext().actorOf(Shard.props(info.getShardId(),
+                                    info.getPeerAddresses(), datastoreContext, schemaContext),
+                                    info.getShardId().toString()));
+                        } else {
                             info.getActor().tell(message, getSelf());
                         }
                     }
@@ -232,25 +275,28 @@ public class ShardManager extends AbstractUntypedPersistentActor {
         String shardName = message.getShardName();
 
         // First see if the there is a local replica for the shard
-        ShardInformation info = localShards.get(shardName);
-        if(info != null) {
-            ActorPath shardPath = info.getActorPath();
-            if (shardPath != null) {
-                getSender()
-                    .tell(
-                        new PrimaryFound(shardPath.toString()).toSerializable(),
-                        getSelf());
-                return;
-            }
+        final ShardInformation info = localShards.get(shardName);
+        if (info != null) {
+            sendResponse(info, new Supplier<Object>() {
+                @Override
+                public Object get() {
+                    return new PrimaryFound(info.getActorPath().toString()).toSerializable();
+                }
+            });
+
+            return;
         }
 
-        List<String> members =
-            configuration.getMembersFromShardName(shardName);
+        List<String> members = configuration.getMembersFromShardName(shardName);
 
         if(cluster.getCurrentMemberName() != null) {
             members.remove(cluster.getCurrentMemberName());
         }
 
+        /**
+         * FIXME: Instead of sending remote shard actor path back to sender,
+         * forward FindPrimary message to remote shard manager
+         */
         // There is no way for us to figure out the primary (for now) so assume
         // that one of the remote nodes is a primary
         for(String memberName : members) {
@@ -296,7 +342,7 @@ public class ShardManager extends AbstractUntypedPersistentActor {
      * runs
      *
      */
-    private void createLocalShards(SchemaContext schemaContext) {
+    private void createLocalShards() {
         String memberName = this.cluster.getCurrentMemberName();
         List<String> memberShardNames =
             this.configuration.getMemberShardNames(memberName);
@@ -305,11 +351,8 @@ public class ShardManager extends AbstractUntypedPersistentActor {
         for(String shardName : memberShardNames){
             ShardIdentifier shardId = getShardIdentifier(memberName, shardName);
             Map<ShardIdentifier, String> peerAddresses = getPeerAddresses(shardName);
-            ActorRef actor = getContext()
-                .actorOf(Shard.props(shardId, peerAddresses, datastoreContext, schemaContext),
-                    shardId.toString());
             localShardActorNames.add(shardId.toString());
-            localShards.put(shardName, new ShardInformation(shardName, actor, peerAddresses));
+            localShards.put(shardName, new ShardInformation(shardName, shardId, peerAddresses));
         }
 
         mBean = ShardManagerInfo.createShardManagerMBean("shard-manager-" + this.type,
@@ -363,56 +406,80 @@ public class ShardManager extends AbstractUntypedPersistentActor {
 
     }
 
-    @Override public String persistenceId() {
+    @Override
+    public String persistenceId() {
         return "shard-manager-" + type;
     }
 
-    @VisibleForTesting public Collection<String> getKnownModules() {
+    @VisibleForTesting
+    Collection<String> getKnownModules() {
         return knownModules;
     }
 
     private class ShardInformation {
+        private final ShardIdentifier shardId;
         private final String shardName;
-        private final ActorRef actor;
-        private final ActorPath actorPath;
+        private ActorRef actor;
+        private ActorPath actorPath;
         private final Map<ShardIdentifier, String> peerAddresses;
+        private boolean shardInitialized = false; // flag that determines if the actor is ready for business
 
-        private ShardInformation(String shardName, ActorRef actor,
-            Map<ShardIdentifier, String> peerAddresses) {
+        private ShardInformation(String shardName, ShardIdentifier shardId,
+                Map<ShardIdentifier, String> peerAddresses) {
             this.shardName = shardName;
-            this.actor = actor;
-            this.actorPath = actor.path();
+            this.shardId = shardId;
             this.peerAddresses = peerAddresses;
         }
 
-        public String getShardName() {
+        String getShardName() {
             return shardName;
         }
 
-        public ActorRef getActor(){
+        ActorRef getActor(){
             return actor;
         }
 
-        public ActorPath getActorPath() {
+        ActorPath getActorPath() {
             return actorPath;
         }
 
-        public void updatePeerAddress(ShardIdentifier peerId, String peerAddress){
+        void setActor(ActorRef actor) {
+            this.actor = actor;
+            this.actorPath = actor.path();
+        }
+
+        ShardIdentifier getShardId() {
+            return shardId;
+        }
+
+        Map<ShardIdentifier, String> getPeerAddresses() {
+            return peerAddresses;
+        }
+
+        void updatePeerAddress(ShardIdentifier peerId, String peerAddress){
             LOG.info("updatePeerAddress for peer {} with address {}", peerId,
                 peerAddress);
             if(peerAddresses.containsKey(peerId)){
                 peerAddresses.put(peerId, peerAddress);
-                if(LOG.isDebugEnabled()) {
-                    LOG.debug(
-                        "Sending PeerAddressResolved for peer {} with address {} to {}",
-                        peerId, peerAddress, actor.path());
-                }
-                actor
-                    .tell(new PeerAddressResolved(peerId, peerAddress),
-                        getSelf());
 
+                if(actor != null) {
+                    if(LOG.isDebugEnabled()) {
+                        LOG.debug("Sending PeerAddressResolved for peer {} with address {} to {}",
+                                peerId, peerAddress, actor.path());
+                    }
+
+                    actor.tell(new PeerAddressResolved(peerId, peerAddress), getSelf());
+                }
             }
         }
+
+        boolean isShardInitialized() {
+            return shardInitialized;
+        }
+
+        void setShardInitialized(boolean shardInitialized) {
+            this.shardInitialized = shardInitialized;
+        }
     }
 
     private static class ShardManagerCreator implements Creator<ShardManager> {
@@ -438,6 +505,8 @@ public class ShardManager extends AbstractUntypedPersistentActor {
     }
 
     static class SchemaContextModules implements Serializable {
+        private static final long serialVersionUID = 1L;
+
         private final Set<String> modules;
 
         SchemaContextModules(Set<String> modules){
index 0e9fd113c53108537c4613569e25cce1805c8877..d12e9997bb29175c7d6c414efdc72b339b706932 100644 (file)
@@ -11,7 +11,6 @@
 package org.opendaylight.controller.cluster.datastore;
 
 import akka.actor.ActorRef;
-
 import org.opendaylight.controller.cluster.datastore.jmx.mbeans.shard.ShardStats;
 import org.opendaylight.controller.cluster.datastore.messages.DataExists;
 import org.opendaylight.controller.cluster.datastore.messages.ReadData;
@@ -27,17 +26,25 @@ public class ShardReadTransaction extends ShardTransaction {
     private final DOMStoreReadTransaction transaction;
 
     public ShardReadTransaction(DOMStoreReadTransaction transaction, ActorRef shardActor,
-            SchemaContext schemaContext, ShardStats shardStats) {
-        super(shardActor, schemaContext, shardStats);
+            SchemaContext schemaContext, ShardStats shardStats, String transactionID) {
+        super(shardActor, schemaContext, shardStats, transactionID);
         this.transaction = transaction;
     }
 
     @Override
     public void handleReceive(Object message) throws Exception {
-        if(ReadData.SERIALIZABLE_CLASS.equals(message.getClass())) {
-            readData(transaction, ReadData.fromSerializable(message));
+        if(message instanceof ReadData) {
+            readData(transaction, (ReadData) message, !SERIALIZED_REPLY);
+
+        } else if (message instanceof DataExists) {
+            dataExists(transaction, (DataExists) message, !SERIALIZED_REPLY);
+
+        } else if(ReadData.SERIALIZABLE_CLASS.equals(message.getClass())) {
+            readData(transaction, ReadData.fromSerializable(message), SERIALIZED_REPLY);
+
         } else if(DataExists.SERIALIZABLE_CLASS.equals(message.getClass())) {
-            dataExists(transaction, DataExists.fromSerializable(message));
+            dataExists(transaction, DataExists.fromSerializable(message), SERIALIZED_REPLY);
+
         } else {
             super.handleReceive(message);
         }
index d04ec233eaf33ae3745eee9fabfd72080f469240..b1fd02d2172cc4c28679c6e4ae86cd31cf2a2657 100644 (file)
@@ -14,49 +14,39 @@ import akka.actor.ActorRef;
 
 import org.opendaylight.controller.cluster.datastore.jmx.mbeans.shard.ShardStats;
 import org.opendaylight.controller.cluster.datastore.messages.DataExists;
-import org.opendaylight.controller.cluster.datastore.messages.DeleteData;
-import org.opendaylight.controller.cluster.datastore.messages.MergeData;
 import org.opendaylight.controller.cluster.datastore.messages.ReadData;
-import org.opendaylight.controller.cluster.datastore.messages.ReadyTransaction;
-import org.opendaylight.controller.cluster.datastore.messages.WriteData;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
-import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransaction;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
 /**
  * @author: syedbahm
  * Date: 8/6/14
  */
-public class ShardReadWriteTransaction extends ShardTransaction {
+public class ShardReadWriteTransaction extends ShardWriteTransaction {
     private final DOMStoreReadWriteTransaction transaction;
 
     public ShardReadWriteTransaction(DOMStoreReadWriteTransaction transaction, ActorRef shardActor,
-            SchemaContext schemaContext, ShardStats shardStats) {
-        super(shardActor, schemaContext, shardStats);
+            SchemaContext schemaContext, ShardStats shardStats, String transactionID) {
+        super(transaction, shardActor, schemaContext, shardStats, transactionID);
         this.transaction = transaction;
     }
 
     @Override
     public void handleReceive(Object message) throws Exception {
-        if(ReadData.SERIALIZABLE_CLASS.equals(message.getClass())) {
-            readData(transaction, ReadData.fromSerializable(message));
-        } else if(WriteData.SERIALIZABLE_CLASS.equals(message.getClass())) {
-            writeData(transaction, WriteData.fromSerializable(message, schemaContext));
-        } else if(MergeData.SERIALIZABLE_CLASS.equals(message.getClass())) {
-            mergeData(transaction, MergeData.fromSerializable(message, schemaContext));
-        } else if(DeleteData.SERIALIZABLE_CLASS.equals(message.getClass())) {
-            deleteData(transaction, DeleteData.fromSerializable(message));
-        } else if(ReadyTransaction.SERIALIZABLE_CLASS.equals(message.getClass())) {
-            readyTransaction(transaction, new ReadyTransaction());
+        if (message instanceof ReadData) {
+            readData(transaction, (ReadData) message, !SERIALIZED_REPLY);
+
+        } else if (message instanceof DataExists) {
+            dataExists(transaction, (DataExists) message, !SERIALIZED_REPLY);
+
+        } else if(ReadData.SERIALIZABLE_CLASS.equals(message.getClass())) {
+            readData(transaction, ReadData.fromSerializable(message), SERIALIZED_REPLY);
+
         } else if(DataExists.SERIALIZABLE_CLASS.equals(message.getClass())) {
-            dataExists(transaction, DataExists.fromSerializable(message));
+            dataExists(transaction, DataExists.fromSerializable(message), SERIALIZED_REPLY);
+
         } else {
             super.handleReceive(message);
         }
     }
-
-    @Override
-    protected DOMStoreTransaction getDOMStoreTransaction() {
-        return transaction;
-    }
 }
index f5ca6e3c5aa2334eb26c52408dd7279f08e33d3a..5289ad33bfb2b2bc3a5008c0211ffccc3b077721 100644 (file)
@@ -13,38 +13,20 @@ 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.common.actor.AbstractUntypedActor;
-
-
 import org.opendaylight.controller.cluster.datastore.exceptions.UnknownMessageException;
 import org.opendaylight.controller.cluster.datastore.jmx.mbeans.shard.ShardStats;
 import org.opendaylight.controller.cluster.datastore.messages.CloseTransaction;
 import org.opendaylight.controller.cluster.datastore.messages.CloseTransactionReply;
 import org.opendaylight.controller.cluster.datastore.messages.DataExists;
 import org.opendaylight.controller.cluster.datastore.messages.DataExistsReply;
-import org.opendaylight.controller.cluster.datastore.messages.DeleteData;
-import org.opendaylight.controller.cluster.datastore.messages.DeleteDataReply;
-import org.opendaylight.controller.cluster.datastore.messages.MergeData;
-import org.opendaylight.controller.cluster.datastore.messages.MergeDataReply;
 import org.opendaylight.controller.cluster.datastore.messages.ReadData;
 import org.opendaylight.controller.cluster.datastore.messages.ReadDataReply;
-import org.opendaylight.controller.cluster.datastore.messages.ReadyTransaction;
-import org.opendaylight.controller.cluster.datastore.messages.ReadyTransactionReply;
-import org.opendaylight.controller.cluster.datastore.messages.WriteData;
-import org.opendaylight.controller.cluster.datastore.messages.WriteDataReply;
-import org.opendaylight.controller.cluster.datastore.modification.CompositeModification;
-import org.opendaylight.controller.cluster.datastore.modification.DeleteModification;
-import org.opendaylight.controller.cluster.datastore.modification.ImmutableCompositeModification;
-import org.opendaylight.controller.cluster.datastore.modification.MergeModification;
-import org.opendaylight.controller.cluster.datastore.modification.MutableCompositeModification;
-import org.opendaylight.controller.cluster.datastore.modification.WriteModification;
 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
-import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransaction;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
@@ -76,34 +58,44 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 public abstract class ShardTransaction extends AbstractUntypedActor {
 
     private final ActorRef shardActor;
-    protected final SchemaContext schemaContext;
+    private final SchemaContext schemaContext;
     private final ShardStats shardStats;
-
-    private final MutableCompositeModification modification = new MutableCompositeModification();
+    private final String transactionID;
+    protected static final boolean SERIALIZED_REPLY = true;
 
     protected ShardTransaction(ActorRef shardActor, SchemaContext schemaContext,
-            ShardStats shardStats) {
+            ShardStats shardStats, String transactionID) {
         this.shardActor = shardActor;
         this.schemaContext = schemaContext;
         this.shardStats = shardStats;
+        this.transactionID = transactionID;
     }
 
     public static Props props(DOMStoreTransaction transaction, ActorRef shardActor,
-            SchemaContext schemaContext,DatastoreContext datastoreContext, ShardStats shardStats) {
+            SchemaContext schemaContext,DatastoreContext datastoreContext, ShardStats shardStats,
+            String transactionID) {
         return Props.create(new ShardTransactionCreator(transaction, shardActor, schemaContext,
-           datastoreContext, shardStats));
+           datastoreContext, shardStats, transactionID));
     }
 
     protected abstract DOMStoreTransaction getDOMStoreTransaction();
 
+    protected ActorRef getShardActor() {
+        return shardActor;
+    }
+
+    protected String getTransactionID() {
+        return transactionID;
+    }
+
+    protected SchemaContext getSchemaContext() {
+        return schemaContext;
+    }
+
     @Override
     public void handleReceive(Object message) throws Exception {
         if (message.getClass().equals(CloseTransaction.SERIALIZABLE_CLASS)) {
             closeTransaction(true);
-        } else if (message instanceof GetCompositedModification) {
-            // This is here for testing only
-            getSender().tell(new GetCompositeModificationReply(
-                    new ImmutableCompositeModification(modification)), getSelf());
         } else if (message instanceof ReceiveTimeout) {
             if(LOG.isDebugEnabled()) {
                 LOG.debug("Got ReceiveTimeout for inactivity - closing Tx");
@@ -124,23 +116,24 @@ public abstract class ShardTransaction extends AbstractUntypedActor {
         getSelf().tell(PoisonPill.getInstance(), getSelf());
     }
 
-    protected void readData(DOMStoreReadTransaction transaction,ReadData message) {
+    protected void readData(DOMStoreReadTransaction transaction, ReadData message, final boolean returnSerialized) {
         final ActorRef sender = getSender();
         final ActorRef self = getSelf();
         final YangInstanceIdentifier path = message.getPath();
         final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> future =
                 transaction.read(path);
 
+
         future.addListener(new Runnable() {
             @Override
             public void run() {
                 try {
                     Optional<NormalizedNode<?, ?>> optional = future.checkedGet();
-                    if (optional.isPresent()) {
-                        sender.tell(new ReadDataReply(schemaContext,optional.get()).toSerializable(), self);
-                    } else {
-                        sender.tell(new ReadDataReply(schemaContext,null).toSerializable(), self);
-                    }
+                    ReadDataReply readDataReply = new ReadDataReply(schemaContext, optional.orNull());
+
+                    sender.tell((returnSerialized ? readDataReply.toSerializable():
+                        readDataReply), self);
+
                 } catch (Exception e) {
                     shardStats.incrementFailedReadTransactionsCount();
                     sender.tell(new akka.actor.Status.Failure(e), self);
@@ -150,68 +143,21 @@ public abstract class ShardTransaction extends AbstractUntypedActor {
         }, getContext().dispatcher());
     }
 
-    protected void dataExists(DOMStoreReadTransaction transaction, DataExists message) {
+    protected void dataExists(DOMStoreReadTransaction transaction, DataExists message,
+        final boolean returnSerialized) {
         final YangInstanceIdentifier path = message.getPath();
 
         try {
             Boolean exists = transaction.exists(path).checkedGet();
-            getSender().tell(new DataExistsReply(exists).toSerializable(), getSelf());
+            DataExistsReply dataExistsReply = new DataExistsReply(exists);
+            getSender().tell(returnSerialized ? dataExistsReply.toSerializable() :
+                dataExistsReply, getSelf());
         } catch (ReadFailedException e) {
             getSender().tell(new akka.actor.Status.Failure(e),getSelf());
         }
 
     }
 
-    protected void writeData(DOMStoreWriteTransaction transaction, WriteData message) {
-        modification.addModification(
-                new WriteModification(message.getPath(), message.getData(),schemaContext));
-        if(LOG.isDebugEnabled()) {
-            LOG.debug("writeData at path : " + message.getPath().toString());
-        }
-        try {
-            transaction.write(message.getPath(), message.getData());
-            getSender().tell(new WriteDataReply().toSerializable(), getSelf());
-        }catch(Exception e){
-            getSender().tell(new akka.actor.Status.Failure(e), getSelf());
-        }
-    }
-
-    protected void mergeData(DOMStoreWriteTransaction transaction, MergeData message) {
-        modification.addModification(
-                new MergeModification(message.getPath(), message.getData(), schemaContext));
-        if(LOG.isDebugEnabled()) {
-            LOG.debug("mergeData at path : " + message.getPath().toString());
-        }
-        try {
-            transaction.merge(message.getPath(), message.getData());
-            getSender().tell(new MergeDataReply().toSerializable(), getSelf());
-        }catch(Exception e){
-            getSender().tell(new akka.actor.Status.Failure(e), getSelf());
-        }
-    }
-
-    protected void deleteData(DOMStoreWriteTransaction transaction, DeleteData message) {
-        if(LOG.isDebugEnabled()) {
-            LOG.debug("deleteData at path : " + message.getPath().toString());
-        }
-        modification.addModification(new DeleteModification(message.getPath()));
-        try {
-            transaction.delete(message.getPath());
-            getSender().tell(new DeleteDataReply().toSerializable(), getSelf());
-        }catch(Exception e){
-            getSender().tell(new akka.actor.Status.Failure(e), getSelf());
-        }
-    }
-
-    protected void readyTransaction(DOMStoreWriteTransaction transaction, ReadyTransaction message) {
-        DOMStoreThreePhaseCommitCohort cohort =  transaction.ready();
-        ActorRef cohortActor = getContext().actorOf(
-            ThreePhaseCommitCohort.props(cohort, shardActor, modification, shardStats), "cohort");
-        getSender()
-        .tell(new ReadyTransactionReply(cohortActor.path()).toSerializable(), getSelf());
-
-    }
-
     private static class ShardTransactionCreator implements Creator<ShardTransaction> {
 
         private static final long serialVersionUID = 1L;
@@ -221,15 +167,17 @@ public abstract class ShardTransaction extends AbstractUntypedActor {
         final SchemaContext schemaContext;
         final DatastoreContext datastoreContext;
         final ShardStats shardStats;
+        final String transactionID;
 
         ShardTransactionCreator(DOMStoreTransaction transaction, ActorRef shardActor,
                 SchemaContext schemaContext, DatastoreContext datastoreContext,
-                ShardStats shardStats) {
+                ShardStats shardStats, String transactionID) {
             this.transaction = transaction;
             this.shardActor = shardActor;
             this.shardStats = shardStats;
             this.schemaContext = schemaContext;
             this.datastoreContext = datastoreContext;
+            this.transactionID = transactionID;
         }
 
         @Override
@@ -237,37 +185,17 @@ public abstract class ShardTransaction extends AbstractUntypedActor {
             ShardTransaction tx;
             if(transaction instanceof DOMStoreReadWriteTransaction) {
                 tx = new ShardReadWriteTransaction((DOMStoreReadWriteTransaction)transaction,
-                        shardActor, schemaContext, shardStats);
+                        shardActor, schemaContext, shardStats, transactionID);
             } else if(transaction instanceof DOMStoreReadTransaction) {
                 tx = new ShardReadTransaction((DOMStoreReadTransaction)transaction, shardActor,
-                        schemaContext, shardStats);
+                        schemaContext, shardStats, transactionID);
             } else {
                 tx = new ShardWriteTransaction((DOMStoreWriteTransaction)transaction,
-                        shardActor, schemaContext, shardStats);
+                        shardActor, schemaContext, shardStats, transactionID);
             }
 
             tx.getContext().setReceiveTimeout(datastoreContext.getShardTransactionIdleTimeout());
             return tx;
         }
     }
-
-    // These classes are in here for test purposes only
-
-    static class GetCompositedModification {
-    }
-
-
-    static class GetCompositeModificationReply {
-        private final CompositeModification modification;
-
-
-        GetCompositeModificationReply(CompositeModification modification) {
-            this.modification = modification;
-        }
-
-
-        public CompositeModification getModification() {
-            return modification;
-        }
-    }
 }
index 8fe94cf468b6b63e78128a5f44ca2b1b7cebdd55..943a82f6f9f03565369062bdd8f7779bea5921f0 100644 (file)
@@ -56,23 +56,26 @@ public class ShardTransactionChain extends AbstractUntypedActor {
         return getContext().parent();
     }
 
-    private ActorRef createTypedTransactionActor(CreateTransaction createTransaction,
-            String transactionId) {
+    private ActorRef createTypedTransactionActor(CreateTransaction createTransaction) {
+        String transactionName = "shard-" + createTransaction.getTransactionId();
         if(createTransaction.getTransactionType() ==
                 TransactionProxy.TransactionType.READ_ONLY.ordinal()) {
             return getContext().actorOf(
                     ShardTransaction.props( chain.newReadOnlyTransaction(), getShardActor(),
-                            schemaContext, datastoreContext, shardStats), transactionId);
+                            schemaContext, datastoreContext, shardStats,
+                            createTransaction.getTransactionId()), transactionName);
         } else if (createTransaction.getTransactionType() ==
                 TransactionProxy.TransactionType.READ_WRITE.ordinal()) {
             return getContext().actorOf(
                     ShardTransaction.props( chain.newReadWriteTransaction(), getShardActor(),
-                            schemaContext, datastoreContext, shardStats), transactionId);
+                            schemaContext, datastoreContext, shardStats,
+                            createTransaction.getTransactionId()), transactionName);
         } else if (createTransaction.getTransactionType() ==
                 TransactionProxy.TransactionType.WRITE_ONLY.ordinal()) {
             return getContext().actorOf(
                     ShardTransaction.props( chain.newWriteOnlyTransaction(), getShardActor(),
-                            schemaContext, datastoreContext, shardStats), transactionId);
+                            schemaContext, datastoreContext, shardStats,
+                            createTransaction.getTransactionId()), transactionName);
         } else {
             throw new IllegalArgumentException (
                     "CreateTransaction message has unidentified transaction type=" +
@@ -82,10 +85,9 @@ public class ShardTransactionChain extends AbstractUntypedActor {
 
     private void createTransaction(CreateTransaction createTransaction) {
 
-        ActorRef transactionActor = createTypedTransactionActor(createTransaction, "shard-" + createTransaction.getTransactionId());
-        getSender()
-            .tell(new CreateTransactionReply(transactionActor.path().toString(),createTransaction.getTransactionId()).toSerializable(),
-                getSelf());
+        ActorRef transactionActor = createTypedTransactionActor(createTransaction);
+        getSender().tell(new CreateTransactionReply(transactionActor.path().toString(),
+                createTransaction.getTransactionId()).toSerializable(), getSelf());
     }
 
     public static Props props(DOMStoreTransactionChain chain, SchemaContext schemaContext,
index 396b27a0423c95bdee59e6678c7c12f8796b6c36..21c210daf252fc4633b12882bb18dfea99779aa5 100644 (file)
 package org.opendaylight.controller.cluster.datastore;
 
 import akka.actor.ActorRef;
-
 import org.opendaylight.controller.cluster.datastore.jmx.mbeans.shard.ShardStats;
 import org.opendaylight.controller.cluster.datastore.messages.DeleteData;
+import org.opendaylight.controller.cluster.datastore.messages.DeleteDataReply;
+import org.opendaylight.controller.cluster.datastore.messages.ForwardedReadyTransaction;
 import org.opendaylight.controller.cluster.datastore.messages.MergeData;
+import org.opendaylight.controller.cluster.datastore.messages.MergeDataReply;
 import org.opendaylight.controller.cluster.datastore.messages.ReadyTransaction;
 import org.opendaylight.controller.cluster.datastore.messages.WriteData;
+import org.opendaylight.controller.cluster.datastore.messages.WriteDataReply;
+import org.opendaylight.controller.cluster.datastore.modification.CompositeModification;
+import org.opendaylight.controller.cluster.datastore.modification.DeleteModification;
+import org.opendaylight.controller.cluster.datastore.modification.ImmutableCompositeModification;
+import org.opendaylight.controller.cluster.datastore.modification.MergeModification;
+import org.opendaylight.controller.cluster.datastore.modification.MutableCompositeModification;
+import org.opendaylight.controller.cluster.datastore.modification.WriteModification;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransaction;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
@@ -26,31 +36,127 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext;
  * Date: 8/6/14
  */
 public class ShardWriteTransaction extends ShardTransaction {
+
+    private final MutableCompositeModification modification = new MutableCompositeModification();
     private final DOMStoreWriteTransaction transaction;
 
     public ShardWriteTransaction(DOMStoreWriteTransaction transaction, ActorRef shardActor,
-            SchemaContext schemaContext, ShardStats shardStats) {
-        super(shardActor, schemaContext, shardStats);
+            SchemaContext schemaContext, ShardStats shardStats, String transactionID) {
+        super(shardActor, schemaContext, shardStats, transactionID);
         this.transaction = transaction;
     }
 
+    @Override
+    protected DOMStoreTransaction getDOMStoreTransaction() {
+        return transaction;
+    }
+
     @Override
     public void handleReceive(Object message) throws Exception {
-        if(WriteData.SERIALIZABLE_CLASS.equals(message.getClass())) {
-            writeData(transaction, WriteData.fromSerializable(message, schemaContext));
+
+        if (message instanceof WriteData) {
+            writeData(transaction, (WriteData) message, !SERIALIZED_REPLY);
+
+        } else if (message instanceof MergeData) {
+            mergeData(transaction, (MergeData) message, !SERIALIZED_REPLY);
+
+        } else if (message instanceof DeleteData) {
+            deleteData(transaction, (DeleteData) message, !SERIALIZED_REPLY);
+
+        } else if (message instanceof ReadyTransaction) {
+            readyTransaction(transaction, new ReadyTransaction(), !SERIALIZED_REPLY);
+
+        } else if(WriteData.SERIALIZABLE_CLASS.equals(message.getClass())) {
+            writeData(transaction, WriteData.fromSerializable(message, getSchemaContext()), SERIALIZED_REPLY);
+
         } else if(MergeData.SERIALIZABLE_CLASS.equals(message.getClass())) {
-            mergeData(transaction, MergeData.fromSerializable(message, schemaContext));
+            mergeData(transaction, MergeData.fromSerializable(message, getSchemaContext()), SERIALIZED_REPLY);
+
         } else if(DeleteData.SERIALIZABLE_CLASS.equals(message.getClass())) {
-            deleteData(transaction, DeleteData.fromSerializable(message));
+            deleteData(transaction, DeleteData.fromSerializable(message), SERIALIZED_REPLY);
+
         } else if(ReadyTransaction.SERIALIZABLE_CLASS.equals(message.getClass())) {
-            readyTransaction(transaction, new ReadyTransaction());
+            readyTransaction(transaction, new ReadyTransaction(), SERIALIZED_REPLY);
+
+        } else if (message instanceof GetCompositedModification) {
+            // This is here for testing only
+            getSender().tell(new GetCompositeModificationReply(
+                    new ImmutableCompositeModification(modification)), getSelf());
         } else {
             super.handleReceive(message);
         }
     }
 
-    @Override
-    protected DOMStoreTransaction getDOMStoreTransaction() {
-        return transaction;
+    private void writeData(DOMStoreWriteTransaction transaction, WriteData message, boolean returnSerialized) {
+        modification.addModification(
+                new WriteModification(message.getPath(), message.getData(), getSchemaContext()));
+        if(LOG.isDebugEnabled()) {
+            LOG.debug("writeData at path : " + message.getPath().toString());
+        }
+        try {
+            transaction.write(message.getPath(), message.getData());
+            WriteDataReply writeDataReply = new WriteDataReply();
+            getSender().tell(returnSerialized ? writeDataReply.toSerializable() : writeDataReply,
+                getSelf());
+        }catch(Exception e){
+            getSender().tell(new akka.actor.Status.Failure(e), getSelf());
+        }
+    }
+
+    private void mergeData(DOMStoreWriteTransaction transaction, MergeData message, boolean returnSerialized) {
+        modification.addModification(
+                new MergeModification(message.getPath(), message.getData(), getSchemaContext()));
+        if(LOG.isDebugEnabled()) {
+            LOG.debug("mergeData at path : " + message.getPath().toString());
+        }
+        try {
+            transaction.merge(message.getPath(), message.getData());
+            MergeDataReply mergeDataReply = new MergeDataReply();
+            getSender().tell(returnSerialized ? mergeDataReply.toSerializable() : mergeDataReply ,
+                getSelf());
+        }catch(Exception e){
+            getSender().tell(new akka.actor.Status.Failure(e), getSelf());
+        }
+    }
+
+    private void deleteData(DOMStoreWriteTransaction transaction, DeleteData message, boolean returnSerialized) {
+        if(LOG.isDebugEnabled()) {
+            LOG.debug("deleteData at path : " + message.getPath().toString());
+        }
+        modification.addModification(new DeleteModification(message.getPath()));
+        try {
+            transaction.delete(message.getPath());
+            DeleteDataReply deleteDataReply = new DeleteDataReply();
+            getSender().tell(returnSerialized ? deleteDataReply.toSerializable() : deleteDataReply,
+                getSelf());
+        }catch(Exception e){
+            getSender().tell(new akka.actor.Status.Failure(e), getSelf());
+        }
+    }
+
+    private void readyTransaction(DOMStoreWriteTransaction transaction, ReadyTransaction message, boolean returnSerialized) {
+        DOMStoreThreePhaseCommitCohort cohort =  transaction.ready();
+
+        getShardActor().forward(new ForwardedReadyTransaction(
+            getTransactionID(), cohort, modification, returnSerialized),
+                getContext());
+    }
+
+    // These classes are in here for test purposes only
+
+    static class GetCompositedModification {
+    }
+
+    static class GetCompositeModificationReply {
+        private final CompositeModification modification;
+
+
+        GetCompositeModificationReply(CompositeModification modification) {
+            this.modification = modification;
+        }
+
+        public CompositeModification getModification() {
+            return modification;
+        }
     }
 }
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohort.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohort.java
deleted file mode 100644 (file)
index df85bb1..0000000
+++ /dev/null
@@ -1,175 +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.cluster.datastore;
-
-import akka.actor.ActorRef;
-import akka.actor.PoisonPill;
-import akka.actor.Props;
-import akka.event.Logging;
-import akka.event.LoggingAdapter;
-import akka.japi.Creator;
-
-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.common.actor.AbstractUntypedActor;
-
-import org.opendaylight.controller.cluster.datastore.jmx.mbeans.shard.ShardStats;
-import org.opendaylight.controller.cluster.datastore.messages.AbortTransaction;
-import org.opendaylight.controller.cluster.datastore.messages.AbortTransactionReply;
-import org.opendaylight.controller.cluster.datastore.messages.CanCommitTransaction;
-import org.opendaylight.controller.cluster.datastore.messages.CanCommitTransactionReply;
-import org.opendaylight.controller.cluster.datastore.messages.CommitTransaction;
-import org.opendaylight.controller.cluster.datastore.messages.ForwardedCommitTransaction;
-import org.opendaylight.controller.cluster.datastore.messages.PreCommitTransaction;
-import org.opendaylight.controller.cluster.datastore.messages.PreCommitTransactionReply;
-import org.opendaylight.controller.cluster.datastore.modification.CompositeModification;
-import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
-
-public class ThreePhaseCommitCohort extends AbstractUntypedActor {
-    private final DOMStoreThreePhaseCommitCohort cohort;
-    private final ActorRef shardActor;
-    private final CompositeModification modification;
-    private final ShardStats shardStats;
-
-    public ThreePhaseCommitCohort(DOMStoreThreePhaseCommitCohort cohort,
-        ActorRef shardActor, CompositeModification modification, ShardStats shardStats) {
-
-        this.cohort = cohort;
-        this.shardActor = shardActor;
-        this.modification = modification;
-        this.shardStats = shardStats;
-    }
-
-    private final LoggingAdapter log =
-        Logging.getLogger(getContext().system(), this);
-
-    public static Props props(final DOMStoreThreePhaseCommitCohort cohort,
-            final ActorRef shardActor, final CompositeModification modification,
-            ShardStats shardStats) {
-        return Props.create(new ThreePhaseCommitCohortCreator(cohort, shardActor, modification,
-                shardStats));
-    }
-
-    @Override
-    public void handleReceive(Object message) throws Exception {
-        if (message.getClass()
-            .equals(CanCommitTransaction.SERIALIZABLE_CLASS)) {
-            canCommit(new CanCommitTransaction());
-        } else if (message.getClass()
-            .equals(PreCommitTransaction.SERIALIZABLE_CLASS)) {
-            preCommit(new PreCommitTransaction());
-        } else if (message.getClass()
-            .equals(CommitTransaction.SERIALIZABLE_CLASS)) {
-            commit(new CommitTransaction());
-        } else if (message.getClass()
-            .equals(AbortTransaction.SERIALIZABLE_CLASS)) {
-            abort(new AbortTransaction());
-        } else {
-            unknownMessage(message);
-        }
-    }
-
-    private void abort(AbortTransaction message) {
-        final ListenableFuture<Void> future = cohort.abort();
-        final ActorRef sender = getSender();
-        final ActorRef self = getSelf();
-
-        Futures.addCallback(future, new FutureCallback<Void>() {
-            @Override
-            public void onSuccess(Void v) {
-                shardStats.incrementAbortTransactionsCount();
-                sender
-                    .tell(new AbortTransactionReply().toSerializable(),
-                    self);
-            }
-
-            @Override
-            public void onFailure(Throwable t) {
-                LOG.error(t, "An exception happened during abort");
-                sender
-                    .tell(new akka.actor.Status.Failure(t), self);
-            }
-        });
-    }
-
-    private void commit(CommitTransaction message) {
-        // Forward the commit to the shard
-        if(log.isDebugEnabled()) {
-            log.debug("Forward commit transaction to Shard {} ", shardActor);
-        }
-        shardActor.forward(new ForwardedCommitTransaction(cohort, modification),
-            getContext());
-
-        getContext().parent().tell(PoisonPill.getInstance(), getSelf());
-
-    }
-
-    private void preCommit(PreCommitTransaction message) {
-        final ListenableFuture<Void> future = cohort.preCommit();
-        final ActorRef sender = getSender();
-        final ActorRef self = getSelf();
-        Futures.addCallback(future, new FutureCallback<Void>() {
-            @Override
-            public void onSuccess(Void v) {
-                sender
-                    .tell(new PreCommitTransactionReply().toSerializable(),
-                        self);
-            }
-
-            @Override
-            public void onFailure(Throwable t) {
-                LOG.error(t, "An exception happened during pre-commit");
-                sender
-                    .tell(new akka.actor.Status.Failure(t), self);
-            }
-        });
-
-    }
-
-    private void canCommit(CanCommitTransaction message) {
-        final ListenableFuture<Boolean> future = cohort.canCommit();
-        final ActorRef sender = getSender();
-        final ActorRef self = getSelf();
-        Futures.addCallback(future, new FutureCallback<Boolean>() {
-            @Override
-            public void onSuccess(Boolean canCommit) {
-                sender.tell(new CanCommitTransactionReply(canCommit)
-                    .toSerializable(), self);
-            }
-
-            @Override
-            public void onFailure(Throwable t) {
-                LOG.error(t, "An exception happened during canCommit");
-                sender
-                    .tell(new akka.actor.Status.Failure(t), self);
-            }
-        });
-    }
-
-    private static class ThreePhaseCommitCohortCreator implements Creator<ThreePhaseCommitCohort> {
-        final DOMStoreThreePhaseCommitCohort cohort;
-        final ActorRef shardActor;
-        final CompositeModification modification;
-        final ShardStats shardStats;
-
-        ThreePhaseCommitCohortCreator(DOMStoreThreePhaseCommitCohort cohort,
-            ActorRef shardActor, CompositeModification modification, ShardStats shardStats) {
-            this.cohort = cohort;
-            this.shardActor = shardActor;
-            this.modification = modification;
-            this.shardStats = shardStats;
-        }
-
-        @Override
-        public ThreePhaseCommitCohort create() throws Exception {
-            return new ThreePhaseCommitCohort(cohort, shardActor, modification, shardStats);
-        }
-    }
-}
index a7a5b31b174e4e0d03db192aa367a43ebe67ad62..6e5ba1c90c998102d8878d6b8e6a7c659a475ea4 100644 (file)
@@ -8,32 +8,25 @@
 
 package org.opendaylight.controller.cluster.datastore;
 
-import akka.actor.ActorPath;
 import akka.actor.ActorSelection;
 import akka.dispatch.Futures;
 import akka.dispatch.OnComplete;
-
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.Lists;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.SettableFuture;
-
 import org.opendaylight.controller.cluster.datastore.messages.AbortTransaction;
 import org.opendaylight.controller.cluster.datastore.messages.AbortTransactionReply;
 import org.opendaylight.controller.cluster.datastore.messages.CanCommitTransaction;
 import org.opendaylight.controller.cluster.datastore.messages.CanCommitTransactionReply;
 import org.opendaylight.controller.cluster.datastore.messages.CommitTransaction;
 import org.opendaylight.controller.cluster.datastore.messages.CommitTransactionReply;
-import org.opendaylight.controller.cluster.datastore.messages.PreCommitTransaction;
-import org.opendaylight.controller.cluster.datastore.messages.PreCommitTransactionReply;
 import org.opendaylight.controller.cluster.datastore.utils.ActorContext;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-
 import scala.concurrent.Future;
 import scala.runtime.AbstractFunction1;
-
 import java.util.Collections;
 import java.util.List;
 
@@ -44,30 +37,33 @@ public class ThreePhaseCommitCohortProxy implements DOMStoreThreePhaseCommitCoho
 
     private static final Logger LOG = LoggerFactory.getLogger(ThreePhaseCommitCohortProxy.class);
 
+    private static final ListenableFuture<Void> IMMEDIATE_SUCCESS =
+            com.google.common.util.concurrent.Futures.immediateFuture(null);
+
     private final ActorContext actorContext;
-    private final List<Future<ActorPath>> cohortPathFutures;
-    private volatile List<ActorPath> cohortPaths;
+    private final List<Future<ActorSelection>> cohortFutures;
+    private volatile List<ActorSelection> cohorts;
     private final String transactionId;
 
     public ThreePhaseCommitCohortProxy(ActorContext actorContext,
-            List<Future<ActorPath>> cohortPathFutures, String transactionId) {
+            List<Future<ActorSelection>> cohortFutures, String transactionId) {
         this.actorContext = actorContext;
-        this.cohortPathFutures = cohortPathFutures;
+        this.cohortFutures = cohortFutures;
         this.transactionId = transactionId;
     }
 
-    private Future<Void> buildCohortPathsList() {
+    private Future<Void> buildCohortList() {
 
-        Future<Iterable<ActorPath>> combinedFutures = Futures.sequence(cohortPathFutures,
+        Future<Iterable<ActorSelection>> combinedFutures = Futures.sequence(cohortFutures,
                 actorContext.getActorSystem().dispatcher());
 
-        return combinedFutures.transform(new AbstractFunction1<Iterable<ActorPath>, Void>() {
+        return combinedFutures.transform(new AbstractFunction1<Iterable<ActorSelection>, Void>() {
             @Override
-            public Void apply(Iterable<ActorPath> paths) {
-                cohortPaths = Lists.newArrayList(paths);
+            public Void apply(Iterable<ActorSelection> actorSelections) {
+                cohorts = Lists.newArrayList(actorSelections);
                 if(LOG.isDebugEnabled()) {
                     LOG.debug("Tx {} successfully built cohort path list: {}",
-                        transactionId, cohortPaths);
+                        transactionId, cohorts);
                 }
                 return null;
             }
@@ -87,12 +83,12 @@ public class ThreePhaseCommitCohortProxy implements DOMStoreThreePhaseCommitCoho
         // extracted from ReadyTransactionReply messages by the Futures that were obtained earlier
         // and passed to us from upstream processing. If any one fails then  we'll fail canCommit.
 
-        buildCohortPathsList().onComplete(new OnComplete<Void>() {
+        buildCohortList().onComplete(new OnComplete<Void>() {
             @Override
             public void onComplete(Throwable failure, Void notUsed) throws Throwable {
                 if(failure != null) {
                     if(LOG.isDebugEnabled()) {
-                        LOG.debug("Tx {}: a cohort path Future failed: {}", transactionId, failure);
+                        LOG.debug("Tx {}: a cohort Future failed: {}", transactionId, failure);
                     }
                     returnFuture.setException(failure);
                 } else {
@@ -112,7 +108,7 @@ public class ThreePhaseCommitCohortProxy implements DOMStoreThreePhaseCommitCoho
         // their canCommit processing. If any one fails then we'll fail canCommit.
 
         Future<Iterable<Object>> combinedFuture =
-                invokeCohorts(new CanCommitTransaction().toSerializable());
+                invokeCohorts(new CanCommitTransaction(transactionId).toSerializable());
 
         combinedFuture.onComplete(new OnComplete<Iterable<Object>>() {
             @Override
@@ -150,14 +146,13 @@ public class ThreePhaseCommitCohortProxy implements DOMStoreThreePhaseCommitCoho
     }
 
     private Future<Iterable<Object>> invokeCohorts(Object message) {
-        List<Future<Object>> futureList = Lists.newArrayListWithCapacity(cohortPaths.size());
-        for(ActorPath actorPath : cohortPaths) {
+        List<Future<Object>> futureList = Lists.newArrayListWithCapacity(cohorts.size());
+        for(ActorSelection cohort : cohorts) {
             if(LOG.isDebugEnabled()) {
-                LOG.debug("Tx {}: Sending {} to cohort {}", transactionId, message, actorPath);
+                LOG.debug("Tx {}: Sending {} to cohort {}", transactionId, message, cohort);
             }
-            ActorSelection cohort = actorContext.actorSelection(actorPath);
 
-            futureList.add(actorContext.executeRemoteOperationAsync(cohort, message));
+            futureList.add(actorContext.executeOperationAsync(cohort, message));
         }
 
         return Futures.sequence(futureList, actorContext.getActorSystem().dispatcher());
@@ -165,8 +160,9 @@ public class ThreePhaseCommitCohortProxy implements DOMStoreThreePhaseCommitCoho
 
     @Override
     public ListenableFuture<Void> preCommit() {
-        return voidOperation("preCommit",  new PreCommitTransaction().toSerializable(),
-                PreCommitTransactionReply.SERIALIZABLE_CLASS, true);
+        // We don't need to do anything here - preCommit is done atomically with the commit phase
+        // by the shard.
+        return IMMEDIATE_SUCCESS;
     }
 
     @Override
@@ -177,13 +173,13 @@ public class ThreePhaseCommitCohortProxy implements DOMStoreThreePhaseCommitCoho
         // exception then that exception will supersede and suppress the original exception. But
         // it's the original exception that is the root cause and of more interest to the client.
 
-        return voidOperation("abort", new AbortTransaction().toSerializable(),
+        return voidOperation("abort", new AbortTransaction(transactionId).toSerializable(),
                 AbortTransactionReply.SERIALIZABLE_CLASS, false);
     }
 
     @Override
     public ListenableFuture<Void> commit() {
-        return voidOperation("commit",  new CommitTransaction().toSerializable(),
+        return voidOperation("commit",  new CommitTransaction(transactionId).toSerializable(),
                 CommitTransactionReply.SERIALIZABLE_CLASS, true);
     }
 
@@ -198,11 +194,11 @@ public class ThreePhaseCommitCohortProxy implements DOMStoreThreePhaseCommitCoho
         // The cohort actor list should already be built at this point by the canCommit phase but,
         // if not for some reason, we'll try to build it here.
 
-        if(cohortPaths != null) {
+        if(cohorts != null) {
             finishVoidOperation(operationName, message, expectedResponseClass, propagateException,
                     returnFuture);
         } else {
-            buildCohortPathsList().onComplete(new OnComplete<Void>() {
+            buildCohortList().onComplete(new OnComplete<Void>() {
                 @Override
                 public void onComplete(Throwable failure, Void notUsed) throws Throwable {
                     if(failure != null) {
@@ -280,7 +276,7 @@ public class ThreePhaseCommitCohortProxy implements DOMStoreThreePhaseCommitCoho
     }
 
     @VisibleForTesting
-    List<Future<ActorPath>> getCohortPathFutures() {
-        return Collections.unmodifiableList(cohortPathFutures);
+    List<Future<ActorSelection>> getCohortFutures() {
+        return Collections.unmodifiableList(cohortFutures);
     }
 }
index b74c89d727c2a1761a7c993272abcab1e4ad9999..b467ee4ddbf56c456c2e9f0f62381eefa173e31d 100644 (file)
@@ -8,7 +8,7 @@
 
 package org.opendaylight.controller.cluster.datastore;
 
-import akka.actor.ActorPath;
+import akka.actor.ActorSelection;
 import akka.dispatch.Futures;
 import org.opendaylight.controller.cluster.datastore.messages.CloseTransactionChain;
 import org.opendaylight.controller.cluster.datastore.utils.ActorContext;
@@ -28,7 +28,7 @@ import java.util.List;
 public class TransactionChainProxy implements DOMStoreTransactionChain{
     private final ActorContext actorContext;
     private final String transactionChainId;
-    private volatile List<Future<ActorPath>> cohortPathFutures = Collections.emptyList();
+    private volatile List<Future<ActorSelection>> cohortFutures = Collections.emptyList();
 
     public TransactionChainProxy(ActorContext actorContext) {
         this.actorContext = actorContext;
@@ -63,14 +63,14 @@ public class TransactionChainProxy implements DOMStoreTransactionChain{
         return transactionChainId;
     }
 
-    public void onTransactionReady(List<Future<ActorPath>> cohortPathFutures){
-        this.cohortPathFutures = cohortPathFutures;
+    public void onTransactionReady(List<Future<ActorSelection>> cohortFutures){
+        this.cohortFutures = cohortFutures;
     }
 
     public void waitTillCurrentTransactionReady(){
         try {
             Await.result(Futures
-                .sequence(this.cohortPathFutures, actorContext.getActorSystem().dispatcher()),
+                .sequence(this.cohortFutures, actorContext.getActorSystem().dispatcher()),
                 actorContext.getOperationDuration());
         } catch (Exception e) {
             throw new IllegalStateException("Failed when waiting for transaction on a chain to become ready", e);
index 6cf16b44268c6c16e26e0658632f61994ee33971..715f48c3492156d1b14005462da2c26aacb1768c 100644 (file)
@@ -8,7 +8,6 @@
 
 package org.opendaylight.controller.cluster.datastore;
 
-import akka.actor.ActorPath;
 import akka.actor.ActorSelection;
 import akka.dispatch.OnComplete;
 
@@ -22,6 +21,7 @@ import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.SettableFuture;
 
+import org.opendaylight.controller.cluster.datastore.exceptions.PrimaryNotFoundException;
 import org.opendaylight.controller.cluster.datastore.identifiers.TransactionIdentifier;
 import org.opendaylight.controller.cluster.datastore.messages.CloseTransaction;
 import org.opendaylight.controller.cluster.datastore.messages.CreateTransaction;
@@ -156,8 +156,8 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction {
             if(remoteTransactionActorsMB.get()) {
                 for(ActorSelection actor : remoteTransactionActors) {
                     LOG.trace("Sending CloseTransaction to {}", actor);
-                    actorContext.sendRemoteOperationAsync(actor,
-                            new CloseTransaction().toSerializable());
+                    actorContext.sendOperationAsync(actor,
+                        new CloseTransaction().toSerializable());
                 }
             }
         }
@@ -314,7 +314,7 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction {
             LOG.debug("Tx {} Trying to get {} transactions ready for commit", identifier,
                 remoteTransactionPaths.size());
         }
-        List<Future<ActorPath>> cohortPathFutures = Lists.newArrayList();
+        List<Future<ActorSelection>> cohortFutures = Lists.newArrayList();
 
         for(TransactionContext transactionContext : remoteTransactionPaths.values()) {
 
@@ -322,14 +322,14 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction {
                 LOG.debug("Tx {} Readying transaction for shard {}", identifier,
                     transactionContext.getShardName());
             }
-            cohortPathFutures.add(transactionContext.readyTransaction());
+            cohortFutures.add(transactionContext.readyTransaction());
         }
 
         if(transactionChainProxy != null){
-            transactionChainProxy.onTransactionReady(cohortPathFutures);
+            transactionChainProxy.onTransactionReady(cohortFutures);
         }
 
-        return new ThreePhaseCommitCohortProxy(actorContext, cohortPathFutures,
+        return new ThreePhaseCommitCohortProxy(actorContext, cohortFutures,
                 identifier.toString());
     }
 
@@ -379,7 +379,12 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction {
         }
 
         try {
-            Object response = actorContext.executeShardOperation(shardName,
+            Optional<ActorSelection> primaryShard = actorContext.findPrimaryShard(shardName);
+            if (!primaryShard.isPresent()) {
+                throw new PrimaryNotFoundException("Primary could not be found for shard " + shardName);
+            }
+
+            Object response = actorContext.executeOperation(primaryShard.get(),
                 new CreateTransaction(identifier.toString(), this.transactionType.ordinal(),
                     getTransactionChainId()).toSerializable());
             if (response.getClass().equals(CreateTransactionReply.SERIALIZABLE_CLASS)) {
@@ -403,8 +408,12 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction {
                     remoteTransactionActorsMB.set(true);
                 }
 
+                // TxActor is always created where the leader of the shard is.
+                // Check if TxActor is created in the same node
+                boolean isTxActorLocal = actorContext.isLocalPath(transactionPath);
+
                 transactionContext = new TransactionContextImpl(shardName, transactionPath,
-                    transactionActor, identifier, actorContext, schemaContext);
+                    transactionActor, identifier, actorContext, schemaContext, isTxActorLocal);
 
                 remoteTransactionPaths.put(shardName, transactionContext);
             } else {
@@ -433,7 +442,7 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction {
 
         void closeTransaction();
 
-        Future<ActorPath> readyTransaction();
+        Future<ActorSelection> readyTransaction();
 
         void writeData(YangInstanceIdentifier path, NormalizedNode<?, ?> data);
 
@@ -478,43 +487,42 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction {
         private final SchemaContext schemaContext;
         private final String actorPath;
         private final ActorSelection actor;
+        private final boolean isTxActorLocal;
 
         private TransactionContextImpl(String shardName, String actorPath,
                 ActorSelection actor, TransactionIdentifier identifier, ActorContext actorContext,
-                SchemaContext schemaContext) {
+                SchemaContext schemaContext, boolean isTxActorLocal) {
             super(shardName, identifier);
             this.actorPath = actorPath;
             this.actor = actor;
             this.actorContext = actorContext;
             this.schemaContext = schemaContext;
+            this.isTxActorLocal = isTxActorLocal;
         }
 
         private ActorSelection getActor() {
             return actor;
         }
 
-        private String getResolvedCohortPath(String cohortPath) {
-            return actorContext.resolvePath(actorPath, cohortPath);
-        }
-
         @Override
         public void closeTransaction() {
             if(LOG.isDebugEnabled()) {
                 LOG.debug("Tx {} closeTransaction called", identifier);
             }
-            actorContext.sendRemoteOperationAsync(getActor(), new CloseTransaction().toSerializable());
+            actorContext.sendOperationAsync(getActor(), new CloseTransaction().toSerializable());
         }
 
         @Override
-        public Future<ActorPath> readyTransaction() {
+        public Future<ActorSelection> readyTransaction() {
             if(LOG.isDebugEnabled()) {
                 LOG.debug("Tx {} readyTransaction called with {} previous recorded operations pending",
                     identifier, recordedOperationFutures.size());
             }
             // Send the ReadyTransaction message to the Tx actor.
 
-            final Future<Object> replyFuture = actorContext.executeRemoteOperationAsync(getActor(),
-                    new ReadyTransaction().toSerializable());
+            ReadyTransaction readyTransaction = new ReadyTransaction();
+            final Future<Object> replyFuture = actorContext.executeOperationAsync(getActor(),
+                isTxActorLocal ? readyTransaction : 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,9 +540,9 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction {
             // Transform the combined Future into a Future that returns the cohort actor path from
             // the ReadyTransactionReply. That's the end result of the ready operation.
 
-            return combinedFutures.transform(new AbstractFunction1<Iterable<Object>, ActorPath>() {
+            return combinedFutures.transform(new AbstractFunction1<Iterable<Object>, ActorSelection>() {
                 @Override
-                public ActorPath apply(Iterable<Object> notUsed) {
+                public ActorSelection apply(Iterable<Object> notUsed) {
                     if(LOG.isDebugEnabled()) {
                         LOG.debug("Tx {} readyTransaction: pending recorded operations succeeded",
                             identifier);
@@ -548,22 +556,15 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction {
 
                     // Note the Future get call here won't block as it's complete.
                     Object serializedReadyReply = replyFuture.value().get().get();
-                    if(serializedReadyReply.getClass().equals(
-                                                     ReadyTransactionReply.SERIALIZABLE_CLASS)) {
-                        ReadyTransactionReply reply = ReadyTransactionReply.fromSerializable(
-                                actorContext.getActorSystem(), serializedReadyReply);
+                    if (serializedReadyReply instanceof ReadyTransactionReply) {
+                        return actorContext.actorSelection(((ReadyTransactionReply)serializedReadyReply).getCohortPath());
 
-                        String resolvedCohortPath = getResolvedCohortPath(
-                                reply.getCohortPath().toString());
+                    } else if(serializedReadyReply.getClass().equals(ReadyTransactionReply.SERIALIZABLE_CLASS)) {
+                        ReadyTransactionReply reply = ReadyTransactionReply.fromSerializable(serializedReadyReply);
+                        return actorContext.actorSelection(reply.getCohortPath());
 
-                        if(LOG.isDebugEnabled()) {
-                            LOG.debug("Tx {} readyTransaction: resolved cohort path {}",
-                                identifier, resolvedCohortPath);
-                        }
-                        return actorContext.actorFor(resolvedCohortPath);
                     } else {
                         // Throwing an exception here will fail the Future.
-
                         throw new IllegalArgumentException(String.format("Invalid reply type {}",
                                 serializedReadyReply.getClass()));
                     }
@@ -576,8 +577,10 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction {
             if(LOG.isDebugEnabled()) {
                 LOG.debug("Tx {} deleteData called path = {}", identifier, path);
             }
-            recordedOperationFutures.add(actorContext.executeRemoteOperationAsync(getActor(),
-                    new DeleteData(path).toSerializable() ));
+
+            DeleteData deleteData = new DeleteData(path);
+            recordedOperationFutures.add(actorContext.executeOperationAsync(getActor(),
+                isTxActorLocal ? deleteData : deleteData.toSerializable()));
         }
 
         @Override
@@ -585,8 +588,10 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction {
             if(LOG.isDebugEnabled()) {
                 LOG.debug("Tx {} mergeData called path = {}", identifier, path);
             }
-            recordedOperationFutures.add(actorContext.executeRemoteOperationAsync(getActor(),
-                    new MergeData(path, data, schemaContext).toSerializable()));
+
+            MergeData mergeData = new MergeData(path, data, schemaContext);
+            recordedOperationFutures.add(actorContext.executeOperationAsync(getActor(),
+                isTxActorLocal ? mergeData : mergeData.toSerializable()));
         }
 
         @Override
@@ -594,8 +599,10 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction {
             if(LOG.isDebugEnabled()) {
                 LOG.debug("Tx {} writeData called path = {}", identifier, path);
             }
-            recordedOperationFutures.add(actorContext.executeRemoteOperationAsync(getActor(),
-                    new WriteData(path, data, schemaContext).toSerializable()));
+
+            WriteData writeData = new WriteData(path, data, schemaContext);
+            recordedOperationFutures.add(actorContext.executeOperationAsync(getActor(),
+                isTxActorLocal ? writeData : writeData.toSerializable()));
         }
 
         @Override
@@ -625,6 +632,7 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction {
                 Future<Iterable<Object>> combinedFutures = akka.dispatch.Futures.sequence(
                         Lists.newArrayList(recordedOperationFutures),
                         actorContext.getActorSystem().dispatcher());
+
                 OnComplete<Iterable<Object>> onComplete = new OnComplete<Iterable<Object>>() {
                     @Override
                     public void onComplete(Throwable failure, Iterable<Object> notUsed)
@@ -669,25 +677,27 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction {
                         if(LOG.isDebugEnabled()) {
                             LOG.debug("Tx {} read operation succeeded", identifier, failure);
                         }
-                        if (readResponse.getClass().equals(ReadDataReply.SERIALIZABLE_CLASS)) {
-                            ReadDataReply reply = ReadDataReply.fromSerializable(schemaContext,
-                                    path, readResponse);
-                            if (reply.getNormalizedNode() == null) {
-                                returnFuture.set(Optional.<NormalizedNode<?, ?>>absent());
-                            } else {
-                                returnFuture.set(Optional.<NormalizedNode<?, ?>>of(
-                                        reply.getNormalizedNode()));
-                            }
+
+                        if (readResponse instanceof ReadDataReply) {
+                            ReadDataReply reply = (ReadDataReply) readResponse;
+                            returnFuture.set(Optional.<NormalizedNode<?, ?>>fromNullable(reply.getNormalizedNode()));
+
+                        } else if (readResponse.getClass().equals(ReadDataReply.SERIALIZABLE_CLASS)) {
+                            ReadDataReply reply = ReadDataReply.fromSerializable(schemaContext, path, readResponse);
+                            returnFuture.set(Optional.<NormalizedNode<?, ?>>fromNullable(reply.getNormalizedNode()));
+
                         } else {
                             returnFuture.setException(new ReadFailedException(
-                                    "Invalid response reading data for path " + path));
+                                "Invalid response reading data for path " + path));
                         }
                     }
                 }
             };
 
-            Future<Object> readFuture = actorContext.executeRemoteOperationAsync(getActor(),
-                    new ReadData(path).toSerializable());
+            ReadData readData = new ReadData(path);
+            Future<Object> readFuture = actorContext.executeOperationAsync(getActor(),
+                isTxActorLocal ? readData : readData.toSerializable());
+
             readFuture.onComplete(onComplete, actorContext.getActorSystem().dispatcher());
         }
 
@@ -762,9 +772,13 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction {
                         if(LOG.isDebugEnabled()) {
                             LOG.debug("Tx {} dataExists operation succeeded", identifier, failure);
                         }
-                        if (response.getClass().equals(DataExistsReply.SERIALIZABLE_CLASS)) {
-                            returnFuture.set(Boolean.valueOf(DataExistsReply.
-                                        fromSerializable(response).exists()));
+
+                        if (response instanceof DataExistsReply) {
+                            returnFuture.set(Boolean.valueOf(((DataExistsReply) response).exists()));
+
+                        } else if (response.getClass().equals(DataExistsReply.SERIALIZABLE_CLASS)) {
+                            returnFuture.set(Boolean.valueOf(DataExistsReply.fromSerializable(response).exists()));
+
                         } else {
                             returnFuture.setException(new ReadFailedException(
                                     "Invalid response checking exists for path " + path));
@@ -773,8 +787,10 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction {
                 }
             };
 
-            Future<Object> future = actorContext.executeRemoteOperationAsync(getActor(),
-                    new DataExists(path).toSerializable());
+            DataExists dataExists = new DataExists(path);
+            Future<Object> future = actorContext.executeOperationAsync(getActor(),
+                isTxActorLocal ? dataExists : dataExists.toSerializable());
+
             future.onComplete(onComplete, actorContext.getActorSystem().dispatcher());
         }
     }
@@ -799,7 +815,7 @@ public class TransactionProxy implements DOMStoreReadWriteTransaction {
         }
 
         @Override
-        public Future<ActorPath> readyTransaction() {
+        public Future<ActorSelection> readyTransaction() {
             if(LOG.isDebugEnabled()) {
                 LOG.debug("Tx {} readyTransaction called", identifier);
             }
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/exceptions/NotInitializedException.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/exceptions/NotInitializedException.java
new file mode 100644 (file)
index 0000000..302d684
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * 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.exceptions;
+
+public class NotInitializedException extends RuntimeException {
+    public NotInitializedException(String message) {
+        super(message);
+    }
+}
index c6928815938058dbddc7bdb8b920c60fa2e0f7da..d65af61ba3f8a957b6f67bdc355035fa93297431 100644 (file)
@@ -10,11 +10,17 @@ package org.opendaylight.controller.cluster.datastore.identifiers;
 
 import com.google.common.base.Preconditions;
 
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
 public class ShardIdentifier {
     private final String shardName;
     private final String memberName;
     private final String type;
 
+    //format and pattern should be in sync
+    private final String format = "%s-shard-%s-%s";
+    private static final Pattern pattern = Pattern.compile("(\\S+)-shard-(\\S+)-(\\S+)");
 
     public ShardIdentifier(String shardName, String memberName, String type) {
 
@@ -60,15 +66,31 @@ public class ShardIdentifier {
     }
 
     @Override public String toString() {
-        StringBuilder builder = new StringBuilder();
-        builder.append(memberName).append("-shard-").append(shardName).append("-").append(type);
-        return builder.toString();
+        //ensure the output of toString matches the pattern above
+        return new StringBuilder(memberName)
+                    .append("-shard-")
+                    .append(shardName)
+                    .append("-")
+                    .append(type)
+                    .toString();
     }
 
     public static Builder builder(){
         return new Builder();
     }
 
+    public String getShardName() {
+        return shardName;
+    }
+
+    public String getMemberName() {
+        return memberName;
+    }
+
+    public String getType() {
+        return type;
+    }
+
     public static class Builder {
         private String shardName;
         private String memberName;
@@ -93,5 +115,15 @@ public class ShardIdentifier {
             return this;
         }
 
+        public Builder fromShardIdString(String shardId){
+            Matcher matcher = pattern.matcher(shardId);
+
+            if (matcher.matches()) {
+                memberName = matcher.group(1);
+                shardName = matcher.group(2);
+                type = matcher.group(3);
+            }
+            return this;
+        }
     }
 }
index 77e81422e6c7c9c11efe925ed35a7da315dcd46a..dd04afcb0b9f4091e73908ba8ef63d262f609353 100644 (file)
@@ -13,14 +13,19 @@ import com.google.common.base.Preconditions;
 public class ShardTransactionIdentifier {
     private final String remoteTransactionId;
 
-    public ShardTransactionIdentifier(String remoteTransactionId) {
-        this.remoteTransactionId = Preconditions.checkNotNull(remoteTransactionId, "remoteTransactionId should not be null");
+    private ShardTransactionIdentifier(String remoteTransactionId) {
+        this.remoteTransactionId = Preconditions.checkNotNull(remoteTransactionId,
+                "remoteTransactionId should not be null");
     }
 
     public static Builder builder(){
         return new Builder();
     }
 
+    public String getRemoteTransactionId() {
+        return remoteTransactionId;
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) {
@@ -45,8 +50,7 @@ public class ShardTransactionIdentifier {
     }
 
     @Override public String toString() {
-        final StringBuilder sb =
-            new StringBuilder();
+        final StringBuilder sb = new StringBuilder();
         sb.append("shard-").append(remoteTransactionId);
         return sb.toString();
     }
index c639064036e82ff80ea5556f769af60bcecbec51..d24e29c9b09a43c80ca2e3e797b105a4f3c0dc33 100644 (file)
@@ -11,10 +11,27 @@ package org.opendaylight.controller.cluster.datastore.messages;
 import org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages;
 
 public class AbortTransaction implements SerializableMessage {
-  public static final Class SERIALIZABLE_CLASS = ThreePhaseCommitCohortMessages.AbortTransaction.class;
+    public static final Class<ThreePhaseCommitCohortMessages.AbortTransaction> SERIALIZABLE_CLASS =
+            ThreePhaseCommitCohortMessages.AbortTransaction.class;
 
-  @Override
-  public Object toSerializable() {
-    return ThreePhaseCommitCohortMessages.AbortTransaction.newBuilder().build();
-  }
+    private final String transactionID;
+
+    public AbortTransaction(String transactionID) {
+        this.transactionID = transactionID;
+    }
+
+    public String getTransactionID() {
+        return transactionID;
+    }
+
+    @Override
+    public Object toSerializable() {
+        return ThreePhaseCommitCohortMessages.AbortTransaction.newBuilder().
+                setTransactionId(transactionID).build();
+    }
+
+    public static AbortTransaction fromSerializable(Object message) {
+        return new AbortTransaction(((ThreePhaseCommitCohortMessages.AbortTransaction)message).
+                getTransactionId());
+    }
 }
index 88e26401f700a449094960aaa784f984e9a27253..79c6b036fa997c94fef08517335d4315cae0629f 100644 (file)
@@ -11,11 +11,11 @@ package org.opendaylight.controller.cluster.datastore.messages;
 import org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages;
 
 public class AbortTransactionReply implements SerializableMessage {
-  public static final Class SERIALIZABLE_CLASS = ThreePhaseCommitCohortMessages.AbortTransactionReply.class;
+    public static final Class<ThreePhaseCommitCohortMessages.AbortTransactionReply> SERIALIZABLE_CLASS =
+            ThreePhaseCommitCohortMessages.AbortTransactionReply.class;
 
-
-  @Override
-  public Object toSerializable() {
-    return ThreePhaseCommitCohortMessages.AbortTransactionReply.newBuilder().build();
-  }
+    @Override
+    public Object toSerializable() {
+        return ThreePhaseCommitCohortMessages.AbortTransactionReply.newBuilder().build();
+    }
 }
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ActorInitialized.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ActorInitialized.java
new file mode 100644 (file)
index 0000000..b034f87
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * 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.messages;
+
+import java.io.Serializable;
+
+public class ActorInitialized implements Serializable {
+}
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ActorNotInitialized.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ActorNotInitialized.java
new file mode 100644 (file)
index 0000000..de25ef9
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * 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.messages;
+
+import java.io.Serializable;
+
+public class ActorNotInitialized implements Serializable {
+}
index 08f81c121f1d115b991005e945f2f03c4a8c1892..565345a44f3d48b321349d97d8d600e992b8946c 100644 (file)
@@ -11,10 +11,26 @@ package org.opendaylight.controller.cluster.datastore.messages;
 import org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages;
 
 public class CanCommitTransaction implements SerializableMessage {
-  public static final Class SERIALIZABLE_CLASS = ThreePhaseCommitCohortMessages.CanCommitTransaction.class;
+    public static final Class<?> SERIALIZABLE_CLASS = ThreePhaseCommitCohortMessages.CanCommitTransaction.class;
 
-  @Override
-  public Object toSerializable() {
-    return  ThreePhaseCommitCohortMessages.CanCommitTransaction.newBuilder().build();
-  }
+    private final String transactionID;
+
+    public CanCommitTransaction(String transactionID) {
+        this.transactionID = transactionID;
+    }
+
+    public String getTransactionID() {
+        return transactionID;
+    }
+
+    @Override
+    public Object toSerializable() {
+        return ThreePhaseCommitCohortMessages.CanCommitTransaction.newBuilder().
+                setTransactionId(transactionID).build();
+    }
+
+    public static CanCommitTransaction fromSerializable(Object message) {
+        return new CanCommitTransaction(((ThreePhaseCommitCohortMessages.CanCommitTransaction)message).
+                getTransactionId());
+    }
 }
index bbcd4de03facf583db5e9def54d9512bde2ebb1b..9c8909c2dd0f339e00ec64ccda57b098d1fd4567 100644 (file)
@@ -11,24 +11,26 @@ package org.opendaylight.controller.cluster.datastore.messages;
 import org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages;
 
 public class CanCommitTransactionReply implements SerializableMessage {
-  public static Class SERIALIZABLE_CLASS = ThreePhaseCommitCohortMessages.CanCommitTransactionReply.class;
-  private final Boolean canCommit;
+    public static Class<ThreePhaseCommitCohortMessages.CanCommitTransactionReply> SERIALIZABLE_CLASS =
+            ThreePhaseCommitCohortMessages.CanCommitTransactionReply.class;
 
-  public CanCommitTransactionReply(Boolean canCommit) {
-    this.canCommit = canCommit;
-  }
+    private final Boolean canCommit;
 
-  public Boolean getCanCommit() {
-    return canCommit;
-  }
+    public CanCommitTransactionReply(Boolean canCommit) {
+        this.canCommit = canCommit;
+    }
 
-  @Override
-  public Object toSerializable() {
-    return  ThreePhaseCommitCohortMessages.CanCommitTransactionReply.newBuilder().setCanCommit(canCommit).build();
-  }
+    public Boolean getCanCommit() {
+        return canCommit;
+    }
 
+    @Override
+    public Object toSerializable() {
+        return ThreePhaseCommitCohortMessages.CanCommitTransactionReply.newBuilder().setCanCommit(canCommit).build();
+    }
 
-  public static CanCommitTransactionReply fromSerializable(Object message) {
-    return  new CanCommitTransactionReply(((ThreePhaseCommitCohortMessages.CanCommitTransactionReply)message).getCanCommit());
-  }
+    public static CanCommitTransactionReply fromSerializable(Object message) {
+        return new CanCommitTransactionReply(
+                ((ThreePhaseCommitCohortMessages.CanCommitTransactionReply) message).getCanCommit());
+    }
 }
index 92138a769c1b4b0d3b3a7f4749313cc4c458002a..d607fe50fef33bc170c58088f2243dd7100c885b 100644 (file)
@@ -11,10 +11,27 @@ package org.opendaylight.controller.cluster.datastore.messages;
 import org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages;
 
 public class CommitTransaction implements SerializableMessage {
-  public static final  Class SERIALIZABLE_CLASS = ThreePhaseCommitCohortMessages.CommitTransaction.class;
+    public static final Class<ThreePhaseCommitCohortMessages.CommitTransaction> SERIALIZABLE_CLASS =
+            ThreePhaseCommitCohortMessages.CommitTransaction.class;
 
-  @Override
-  public Object toSerializable() {
-    return  ThreePhaseCommitCohortMessages.CommitTransaction.newBuilder().build();
-  }
+    private final String transactionID;
+
+    public CommitTransaction(String transactionID) {
+        this.transactionID = transactionID;
+    }
+
+    public String getTransactionID() {
+        return transactionID;
+    }
+
+    @Override
+    public Object toSerializable() {
+        return ThreePhaseCommitCohortMessages.CommitTransaction.newBuilder().setTransactionId(
+                transactionID).build();
+    }
+
+    public static CommitTransaction fromSerializable(Object message) {
+        return new CommitTransaction(((ThreePhaseCommitCohortMessages.
+                CommitTransaction)message).getTransactionId());
+    }
 }
index 5751b71037ba84e97a68834c8e28a1399e7c1d36..3d4a168450bbf4ef07b23a1071e7a6678fba3c13 100644 (file)
@@ -11,11 +11,11 @@ package org.opendaylight.controller.cluster.datastore.messages;
 import org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages;
 
 public class CommitTransactionReply implements SerializableMessage {
+    public static final Class<ThreePhaseCommitCohortMessages.CommitTransactionReply> SERIALIZABLE_CLASS =
+            ThreePhaseCommitCohortMessages.CommitTransactionReply.class;
 
-  public static final Class SERIALIZABLE_CLASS = ThreePhaseCommitCohortMessages.CommitTransactionReply.class;
-
-  @Override
-  public Object toSerializable() {
-    return  ThreePhaseCommitCohortMessages.CommitTransactionReply.newBuilder().build();
-  }
+    @Override
+    public Object toSerializable() {
+        return ThreePhaseCommitCohortMessages.CommitTransactionReply.newBuilder().build();
+    }
 }
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CreateTransactionChain.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CreateTransactionChain.java
deleted file mode 100644 (file)
index 8dd04e5..0000000
+++ /dev/null
@@ -1,20 +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.cluster.datastore.messages;
-
-import org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages;
-
-public class CreateTransactionChain implements SerializableMessage{
-  public static final Class SERIALIZABLE_CLASS = ShardTransactionChainMessages.CreateTransactionChain.class;
-
-  @Override
-  public Object toSerializable() {
-    return  ShardTransactionChainMessages.CreateTransactionChain.newBuilder().build();
-  }
-}
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CreateTransactionChainReply.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CreateTransactionChainReply.java
deleted file mode 100644 (file)
index 4a49762..0000000
+++ /dev/null
@@ -1,39 +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.cluster.datastore.messages;
-
-import akka.actor.ActorPath;
-import akka.actor.ActorSystem;
-import org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages;
-
-public class CreateTransactionChainReply implements SerializableMessage {
-  public static final Class SERIALIZABLE_CLASS = ShardTransactionChainMessages.CreateTransactionChainReply.class;
-  private final ActorPath transactionChainPath;
-
-  public CreateTransactionChainReply(ActorPath transactionChainPath) {
-    this.transactionChainPath = transactionChainPath;
-  }
-
-  public ActorPath getTransactionChainPath() {
-    return transactionChainPath;
-  }
-
-  @Override
-  public ShardTransactionChainMessages.CreateTransactionChainReply toSerializable() {
-    return ShardTransactionChainMessages.CreateTransactionChainReply.newBuilder()
-        .setTransactionChainPath(transactionChainPath.toString()).build();
-  }
-
-  public static CreateTransactionChainReply fromSerializable(ActorSystem actorSystem,Object serializable){
-    ShardTransactionChainMessages.CreateTransactionChainReply o = (ShardTransactionChainMessages.CreateTransactionChainReply) serializable;
-    return new CreateTransactionChainReply(
-        actorSystem.actorFor(o.getTransactionChainPath()).path());
-  }
-
-}
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ForwardedCommitTransaction.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ForwardedCommitTransaction.java
deleted file mode 100644 (file)
index 0104993..0000000
+++ /dev/null
@@ -1,30 +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.cluster.datastore.messages;
-
-import org.opendaylight.controller.cluster.datastore.modification.Modification;
-import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
-
-public class ForwardedCommitTransaction {
-  private final DOMStoreThreePhaseCommitCohort cohort;
-  private final Modification modification;
-
-  public ForwardedCommitTransaction(DOMStoreThreePhaseCommitCohort cohort, Modification modification){
-    this.cohort = cohort;
-    this.modification = modification;
-  }
-
-  public DOMStoreThreePhaseCommitCohort getCohort() {
-    return cohort;
-  }
-
-  public Modification getModification() {
-    return modification;
-  }
-}
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ForwardedReadyTransaction.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/ForwardedReadyTransaction.java
new file mode 100644 (file)
index 0000000..180108f
--- /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.cluster.datastore.messages;
+
+import org.opendaylight.controller.cluster.datastore.modification.Modification;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
+
+/**
+ * Transaction ReadyTransaction message that is forwarded to the local Shard from the ShardTransaction.
+ *
+ * @author Thomas Pantelis
+ */
+public class ForwardedReadyTransaction {
+    private final String transactionID;
+    private final DOMStoreThreePhaseCommitCohort cohort;
+    private final Modification modification;
+    private final boolean returnSerialized;
+
+    public ForwardedReadyTransaction(String transactionID, DOMStoreThreePhaseCommitCohort cohort,
+            Modification modification, boolean returnSerialized) {
+        this.transactionID = transactionID;
+        this.cohort = cohort;
+        this.modification = modification;
+        this.returnSerialized = returnSerialized;
+
+    }
+
+    public String getTransactionID() {
+        return transactionID;
+    }
+
+    public DOMStoreThreePhaseCommitCohort getCohort() {
+        return cohort;
+    }
+
+    public Modification getModification() {
+        return modification;
+    }
+
+    public boolean isReturnSerialized() {
+        return returnSerialized;
+    }
+}
index 5273dc247925608326f9756e5dcbb061b106e5e2..eee489177a5d1496b78bd47a8bf873d959082e06 100644 (file)
@@ -8,32 +8,33 @@
 
 package org.opendaylight.controller.cluster.datastore.messages;
 
-import akka.actor.ActorPath;
-import akka.actor.ActorSystem;
 import org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionMessages;
 
 public class ReadyTransactionReply implements SerializableMessage {
-  public static final Class SERIALIZABLE_CLASS = ShardTransactionMessages.ReadyTransactionReply.class;
-  private final ActorPath cohortPath;
+    public static final Class<ShardTransactionMessages.ReadyTransactionReply> SERIALIZABLE_CLASS =
+            ShardTransactionMessages.ReadyTransactionReply.class;
 
-  public ReadyTransactionReply(ActorPath cohortPath) {
+    private final String cohortPath;
 
-    this.cohortPath = cohortPath;
-  }
+    public ReadyTransactionReply(String cohortPath) {
 
-  public ActorPath getCohortPath() {
-    return cohortPath;
-  }
+        this.cohortPath = cohortPath;
+    }
 
-  @Override
-  public ShardTransactionMessages.ReadyTransactionReply toSerializable() {
-    return ShardTransactionMessages.ReadyTransactionReply.newBuilder()
-        .setActorPath(cohortPath.toString()).build();
-  }
+    public String getCohortPath() {
+        return cohortPath;
+    }
 
-  public static ReadyTransactionReply fromSerializable(ActorSystem actorSystem,Object serializable){
-    ShardTransactionMessages.ReadyTransactionReply o = (ShardTransactionMessages.ReadyTransactionReply) serializable;
-    return new ReadyTransactionReply(
-        actorSystem.actorFor(o.getActorPath()).path());
-  }
+    @Override
+    public ShardTransactionMessages.ReadyTransactionReply toSerializable() {
+        return ShardTransactionMessages.ReadyTransactionReply.newBuilder().
+                setActorPath(cohortPath).build();
+    }
+
+    public static ReadyTransactionReply fromSerializable(Object serializable) {
+        ShardTransactionMessages.ReadyTransactionReply o =
+                (ShardTransactionMessages.ReadyTransactionReply) serializable;
+
+        return new ReadyTransactionReply(o.getActorPath());
+    }
 }
index 8ba333d2799a5177c7b1b8b5b09ab6b4ec87d126..314ae916de1444349816988089011d82b7cd9c8b 100644 (file)
@@ -13,12 +13,14 @@ import akka.actor.ActorRef;
 import akka.actor.ActorSelection;
 import akka.actor.ActorSystem;
 import akka.actor.PoisonPill;
-import akka.pattern.Patterns;
 import akka.util.Timeout;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
 import org.opendaylight.controller.cluster.datastore.ClusterWrapper;
 import org.opendaylight.controller.cluster.datastore.Configuration;
-import org.opendaylight.controller.cluster.datastore.exceptions.PrimaryNotFoundException;
+import org.opendaylight.controller.cluster.datastore.exceptions.NotInitializedException;
 import org.opendaylight.controller.cluster.datastore.exceptions.TimeoutException;
+import org.opendaylight.controller.cluster.datastore.messages.ActorNotInitialized;
 import org.opendaylight.controller.cluster.datastore.messages.FindLocalShard;
 import org.opendaylight.controller.cluster.datastore.messages.FindPrimary;
 import org.opendaylight.controller.cluster.datastore.messages.LocalShardFound;
@@ -31,9 +33,7 @@ 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;
 
 /**
@@ -101,14 +101,17 @@ public class ActorContext {
     }
 
     /**
-     * Finds the primary for a given shard
+     * Finds the primary shard for the given shard name
      *
      * @param shardName
      * @return
      */
-    public ActorSelection findPrimary(String shardName) {
-        String path = findPrimaryPath(shardName);
-        return actorSystem.actorSelection(path);
+    public Optional<ActorSelection> findPrimaryShard(String shardName) {
+        String path = findPrimaryPathOrNull(shardName);
+        if (path == null){
+            return Optional.absent();
+        }
+        return Optional.of(actorSystem.actorSelection(path));
     }
 
     /**
@@ -118,36 +121,36 @@ public class ActorContext {
      * @return a reference to a local shard actor which represents the shard
      *         specified by the shardName
      */
-    public ActorRef findLocalShard(String shardName) {
-        Object result = executeLocalOperation(shardManager,
-            new FindLocalShard(shardName));
+    public Optional<ActorRef> findLocalShard(String shardName) {
+        Object result = executeOperation(shardManager, new FindLocalShard(shardName));
 
         if (result instanceof LocalShardFound) {
             LocalShardFound found = (LocalShardFound) result;
-
-            if(LOG.isDebugEnabled()) {
-                LOG.debug("Local shard found {}", found.getPath());
-            }
-            return found.getPath();
+            LOG.debug("Local shard found {}", found.getPath());
+            return Optional.of(found.getPath());
         }
 
-        return null;
+        return Optional.absent();
     }
 
 
-    public String findPrimaryPath(String shardName) {
-        Object result = executeLocalOperation(shardManager,
-            new FindPrimary(shardName).toSerializable());
+    private String findPrimaryPathOrNull(String shardName) {
+        Object result = executeOperation(shardManager, new FindPrimary(shardName).toSerializable());
 
         if (result.getClass().equals(PrimaryFound.SERIALIZABLE_CLASS)) {
             PrimaryFound found = PrimaryFound.fromSerializable(result);
 
-            if(LOG.isDebugEnabled()) {
-                LOG.debug("Primary found {}", found.getPrimaryPath());
-            }
+            LOG.debug("Primary found {}", found.getPrimaryPath());
             return found.getPrimaryPath();
+
+        } else if (result.getClass().equals(ActorNotInitialized.class)){
+            throw new NotInitializedException(
+                String.format("Found primary shard[%s] but its not initialized yet. Please try again later", shardName)
+            );
+
+        } else {
+            return null;
         }
-        throw new PrimaryNotFoundException("Could not find primary for shardName " + shardName);
     }
 
 
@@ -158,16 +161,25 @@ public class ActorContext {
      * @param message
      * @return The response of the operation
      */
-    public Object executeLocalOperation(ActorRef actor, Object message) {
-        Future<Object> future = ask(actor, message, operationTimeout);
+    public Object executeOperation(ActorRef actor, Object message) {
+        Future<Object> future = executeOperationAsync(actor, message, operationTimeout);
 
         try {
             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. Try again later.", e);
         }
     }
 
+    public Future<Object> executeOperationAsync(ActorRef actor, Object message, Timeout timeout) {
+        Preconditions.checkArgument(actor != null, "actor must not be null");
+        Preconditions.checkArgument(message != null, "message must not be null");
+
+        LOG.debug("Sending message {} to {}", message.getClass().toString(), actor.toString());
+        return ask(actor, message, timeout);
+    }
+
     /**
      * Execute an operation on a remote actor and wait for it's response
      *
@@ -175,19 +187,14 @@ public class ActorContext {
      * @param message
      * @return
      */
-    public Object executeRemoteOperation(ActorSelection actor, Object message) {
-
-        if(LOG.isDebugEnabled()) {
-            LOG.debug("Sending remote message {} to {}", message.getClass().toString(),
-                actor.toString());
-        }
-        Future<Object> future = ask(actor, message, operationTimeout);
+    public Object executeOperation(ActorSelection actor, Object message) {
+        Future<Object> future = executeOperationAsync(actor, message);
 
         try {
             return Await.result(future, operationDuration);
         } catch (Exception e) {
             throw new TimeoutException("Sending message " + message.getClass().toString() +
-                    " to actor " + actor.toString() + " failed, e);
+                    " to actor " + actor.toString() + " failed. Try again later.", e);
         }
     }
 
@@ -198,11 +205,12 @@ public class ActorContext {
      * @param message the message to send
      * @return a Future containing the eventual result
      */
-    public Future<Object> executeRemoteOperationAsync(ActorSelection actor, Object message) {
+    public Future<Object> executeOperationAsync(ActorSelection actor, Object message) {
+        Preconditions.checkArgument(actor != null, "actor must not be null");
+        Preconditions.checkArgument(message != null, "message must not be null");
+
+        LOG.debug("Sending message {} to {}", message.getClass().toString(), actor.toString());
 
-        if(LOG.isDebugEnabled()) {
-            LOG.debug("Sending remote message {} to {}", message.getClass().toString(), actor.toString());
-        }
         return ask(actor, message, operationTimeout);
     }
 
@@ -213,117 +221,22 @@ public class ActorContext {
      * @param actor the ActorSelection
      * @param message the message to send
      */
-    public void sendRemoteOperationAsync(ActorSelection actor, Object message) {
-        actor.tell(message, ActorRef.noSender());
-    }
-
-    public void sendShardOperationAsync(String shardName, Object message) {
-        ActorSelection primary = findPrimary(shardName);
-
-        primary.tell(message, ActorRef.noSender());
-    }
-
-
-    /**
-     * Execute an operation on the primary for a given shard
-     * <p>
-     * This method first finds the primary for a given shard ,then sends
-     * the message to the remote shard and waits for a response
-     * </p>
-     *
-     * @param shardName
-     * @param message
-     * @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) {
-        ActorSelection primary = findPrimary(shardName);
+    public void sendOperationAsync(ActorSelection actor, Object message) {
+        Preconditions.checkArgument(actor != null, "actor must not be null");
+        Preconditions.checkArgument(message != null, "message must not be null");
 
-        return executeRemoteOperation(primary, message);
-    }
+        LOG.debug("Sending message {} to {}", message.getClass().toString(), actor.toString());
 
-    /**
-     * Execute an operation on the the local shard only
-     * <p>
-     *     This method first finds the address of the local shard if any. It then
-     *     executes the operation on it.
-     * </p>
-     *
-     * @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
-     * @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) {
-        ActorRef local = findLocalShard(shardName);
-
-        if(local != null) {
-            return executeLocalOperation(local, message);
-        }
-
-        return null;
-    }
-
-
-    /**
-     * Execute an operation on the the local shard only asynchronously
-     *
-     * <p>
-     *     This method first finds the address of the local shard if any. It then
-     *     executes the operation on it.
-     * </p>
-     *
-     * @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 timeout the amount of time that this method should wait for a response before timing out
-     * @return null if the shard could not be located else a future on which the caller can wait
-     *
-     */
-    public Future executeLocalShardOperationAsync(String shardName, Object message, Timeout timeout) {
-        ActorRef local = findLocalShard(shardName);
-        if(local == null){
-            return null;
-        }
-        return Patterns.ask(local, message, timeout);
+        actor.tell(message, ActorRef.noSender());
     }
 
-
-
     public void shutdown() {
         shardManager.tell(PoisonPill.getInstance(), null);
         actorSystem.shutdown();
     }
 
-    /**
-     * @deprecated Need to stop using this method. There are ways to send a
-     * remote ActorRef as a string which should be used instead of this hack
-     *
-     * @param primaryPath
-     * @param localPathOfRemoteActor
-     * @return
-     */
-    @Deprecated
-    public String resolvePath(final String primaryPath,
-        final String localPathOfRemoteActor) {
-        StringBuilder builder = new StringBuilder();
-        String[] primaryPathElements = primaryPath.split("/");
-        builder.append(primaryPathElements[0]).append("//")
-            .append(primaryPathElements[1]).append(primaryPathElements[2]);
-        String[] remotePathElements = localPathOfRemoteActor.split("/");
-        for (int i = 3; i < remotePathElements.length; i++) {
-            builder.append("/").append(remotePathElements[i]);
-        }
-
-        return builder.toString();
-
-    }
-
-    public ActorPath actorFor(String path){
-        return actorSystem.actorFor(path).path();
+    public ClusterWrapper getClusterWrapper() {
+        return clusterWrapper;
     }
 
     public String getCurrentMemberName(){
@@ -337,10 +250,13 @@ public class ActorContext {
      */
     public void broadcast(Object message){
         for(String shardName : configuration.getAllShardNames()){
-            try {
-                sendShardOperationAsync(shardName, message);
-            } catch(Exception e){
-                LOG.warn("broadcast failed to send message " +  message.getClass().getSimpleName() + " to shard " + shardName, e);
+
+            Optional<ActorSelection> primary = findPrimaryShard(shardName);
+            if (primary.isPresent()) {
+                primary.get().tell(message, ActorRef.noSender());
+            } else {
+                LOG.warn("broadcast failed to send message {} to shard {}. Primary not found",
+                        message.getClass().getSimpleName(), shardName);
             }
         }
     }
@@ -348,4 +264,30 @@ public class ActorContext {
     public FiniteDuration getOperationDuration() {
         return operationDuration;
     }
+
+    public boolean isLocalPath(String path) {
+        String selfAddress = clusterWrapper.getSelfAddress();
+        if (path == null || selfAddress == null) {
+            return false;
+        }
+
+        int atIndex1 = path.indexOf("@");
+        int atIndex2 = selfAddress.indexOf("@");
+
+        if (atIndex1 == -1 || atIndex2 == -1) {
+            return false;
+        }
+
+        int slashIndex1 = path.indexOf("/", atIndex1);
+        int slashIndex2 = selfAddress.indexOf("/", atIndex2);
+
+        if (slashIndex1 == -1 || slashIndex2 == -1) {
+            return false;
+        }
+
+        String hostPort1 = path.substring(atIndex1, slashIndex1);
+        String hostPort2 = selfAddress.substring(atIndex2, slashIndex2);
+
+        return hostPort1.equals(hostPort2);
+    }
 }
index 84614bd7bb43a0bbf43f3fe055673f64fe2cd10d..de33f55b96b6a840a8d8fa36dfe5f29aa1195660 100644 (file)
@@ -40,18 +40,25 @@ public class DistributedConfigDataStoreProviderModule extends
             props = new ConfigProperties();
         }
 
-        DatastoreContext datastoreContext = new DatastoreContext("DistributedConfigDatastore",
-                InMemoryDOMDataStoreConfigProperties.create(
+        DatastoreContext datastoreContext = DatastoreContext.newBuilder()
+                .dataStoreMXBeanType("DistributedConfigDatastore")
+                .dataStoreProperties(InMemoryDOMDataStoreConfigProperties.create(
                         props.getMaxShardDataChangeExecutorPoolSize().getValue().intValue(),
                         props.getMaxShardDataChangeExecutorQueueSize().getValue().intValue(),
                         props.getMaxShardDataChangeListenerQueueSize().getValue().intValue(),
-                        props.getMaxShardDataStoreExecutorQueueSize().getValue().intValue()),
-                Duration.create(props.getShardTransactionIdleTimeoutInMinutes().getValue(),
-                        TimeUnit.MINUTES),
-                props.getOperationTimeoutInSeconds().getValue(),
-                props.getShardJournalRecoveryLogBatchSize().getValue().intValue(),
-                props.getShardSnapshotBatchCount().getValue().intValue(),
-                props.getShardHearbeatIntervalInMillis().getValue());
+                        props.getMaxShardDataStoreExecutorQueueSize().getValue().intValue()))
+                .shardTransactionIdleTimeout(Duration.create(
+                        props.getShardTransactionIdleTimeoutInMinutes().getValue(), TimeUnit.MINUTES))
+                .operationTimeoutInSeconds(props.getOperationTimeoutInSeconds().getValue())
+                .shardJournalRecoveryLogBatchSize(props.getShardJournalRecoveryLogBatchSize().
+                        getValue().intValue())
+                .shardSnapshotBatchCount(props.getShardSnapshotBatchCount().getValue().intValue())
+                .shardHeartbeatIntervalInMillis(props.getShardHearbeatIntervalInMillis().getValue())
+                .shardTransactionCommitTimeoutInSeconds(
+                        props.getShardTransactionCommitTimeoutInSeconds().getValue().intValue())
+                .shardTransactionCommitQueueCapacity(
+                        props.getShardTransactionCommitQueueCapacity().getValue().intValue())
+                .build();
 
         return DistributedDataStoreFactory.createInstance("config", getConfigSchemaServiceDependency(),
                 datastoreContext, bundleContext);
index 3183527eb032d287623c03e1a4fc57bca9252f2d..ee1859d9cacf27efe9517a07fe2be0a56a7f3a9c 100644 (file)
@@ -40,18 +40,25 @@ public class DistributedOperationalDataStoreProviderModule extends
             props = new OperationalProperties();
         }
 
-        DatastoreContext datastoreContext = new DatastoreContext("DistributedOperationalDatastore",
-                InMemoryDOMDataStoreConfigProperties.create(
+        DatastoreContext datastoreContext = DatastoreContext.newBuilder()
+                .dataStoreMXBeanType("DistributedOperationalDatastore")
+                .dataStoreProperties(InMemoryDOMDataStoreConfigProperties.create(
                         props.getMaxShardDataChangeExecutorPoolSize().getValue().intValue(),
                         props.getMaxShardDataChangeExecutorQueueSize().getValue().intValue(),
                         props.getMaxShardDataChangeListenerQueueSize().getValue().intValue(),
-                        props.getMaxShardDataStoreExecutorQueueSize().getValue().intValue()),
-                Duration.create(props.getShardTransactionIdleTimeoutInMinutes().getValue(),
-                        TimeUnit.MINUTES),
-                props.getOperationTimeoutInSeconds().getValue(),
-                props.getShardJournalRecoveryLogBatchSize().getValue().intValue(),
-                props.getShardSnapshotBatchCount().getValue().intValue(),
-                props.getShardHearbeatIntervalInMillis().getValue());
+                        props.getMaxShardDataStoreExecutorQueueSize().getValue().intValue()))
+                .shardTransactionIdleTimeout(Duration.create(
+                        props.getShardTransactionIdleTimeoutInMinutes().getValue(), TimeUnit.MINUTES))
+                .operationTimeoutInSeconds(props.getOperationTimeoutInSeconds().getValue())
+                .shardJournalRecoveryLogBatchSize(props.getShardJournalRecoveryLogBatchSize().
+                        getValue().intValue())
+                .shardSnapshotBatchCount(props.getShardSnapshotBatchCount().getValue().intValue())
+                .shardHeartbeatIntervalInMillis(props.getShardHearbeatIntervalInMillis().getValue())
+                .shardTransactionCommitTimeoutInSeconds(
+                        props.getShardTransactionCommitTimeoutInSeconds().getValue().intValue())
+                .shardTransactionCommitQueueCapacity(
+                        props.getShardTransactionCommitQueueCapacity().getValue().intValue())
+                .build();
 
         return DistributedDataStoreFactory.createInstance("operational",
                 getOperationalSchemaServiceDependency(), datastoreContext, bundleContext);
index af43f953ffb52ffdd24bd892fe60d8369a0d74da..167d530d18e3c47412c5cd77f52e19081f3b35a7 100644 (file)
@@ -70,7 +70,7 @@ module distributed-datastore-provider {
          leaf max-shard-data-change-listener-queue-size {
             default 1000;
             type non-zero-uint32-type;
-            description "The maximum queue size for each shard's data store data change listeners.";
+            description "The maximum queue size for each shard's data store data change listener.";
          }
 
          leaf max-shard-data-store-executor-queue-size {
@@ -109,6 +109,18 @@ module distributed-datastore-provider {
             description "The maximum number of journal log entries to batch on recovery for a shard before committing to the data store.";
          }
 
+         leaf shard-transaction-commit-timeout-in-seconds {
+            default 30;
+            type non-zero-uint32-type;
+            description "The maximum amount of time a shard transaction three-phase commit can be idle without receiving the next messages before it aborts the transaction";
+         }
+
+         leaf shard-transaction-commit-queue-capacity {
+            default 20000;
+            type non-zero-uint32-type;
+            description "The maximum allowed capacity for each shard's transaction commit queue.";
+         }
+
          leaf enable-metric-capture {
             default false;
             type boolean;
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/BasicIntegrationTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/BasicIntegrationTest.java
deleted file mode 100644 (file)
index 7b82630..0000000
+++ /dev/null
@@ -1,204 +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.cluster.datastore;
-
-import akka.actor.ActorPath;
-import akka.actor.ActorRef;
-import akka.actor.ActorSelection;
-import akka.actor.Props;
-import akka.event.Logging;
-import akka.testkit.JavaTestKit;
-import org.junit.Test;
-import org.opendaylight.controller.cluster.datastore.identifiers.ShardIdentifier;
-import org.opendaylight.controller.cluster.datastore.messages.CommitTransaction;
-import org.opendaylight.controller.cluster.datastore.messages.CreateTransaction;
-import org.opendaylight.controller.cluster.datastore.messages.CreateTransactionReply;
-import org.opendaylight.controller.cluster.datastore.messages.PreCommitTransaction;
-import org.opendaylight.controller.cluster.datastore.messages.PreCommitTransactionReply;
-import org.opendaylight.controller.cluster.datastore.messages.ReadyTransaction;
-import org.opendaylight.controller.cluster.datastore.messages.ReadyTransactionReply;
-import org.opendaylight.controller.cluster.datastore.messages.UpdateSchemaContext;
-import org.opendaylight.controller.cluster.datastore.messages.WriteData;
-import org.opendaylight.controller.cluster.datastore.messages.WriteDataReply;
-import org.opendaylight.controller.md.cluster.datastore.model.TestModel;
-import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import scala.concurrent.Await;
-import scala.concurrent.Future;
-import scala.concurrent.duration.FiniteDuration;
-
-import java.util.Collections;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertTrue;
-import static org.junit.Assert.assertNotNull;
-
-public class BasicIntegrationTest extends AbstractActorTest {
-
-    @Test
-    public void integrationTest() throws Exception{
-        // System.setProperty("shard.persistent", "true");
-        // This test will
-        // - create a Shard
-        // - initiate a transaction
-        // - write something
-        // - read the transaction for commit
-        // - commit the transaction
-
-
-        new JavaTestKit(getSystem()) {{
-            final ShardIdentifier identifier =
-                ShardIdentifier.builder().memberName("member-1")
-                    .shardName("inventory").type("config").build();
-
-            final SchemaContext schemaContext = TestModel.createTestContext();
-            DatastoreContext datastoreContext = new DatastoreContext();
-
-            final Props props = Shard.props(identifier, Collections.EMPTY_MAP, datastoreContext, TestModel.createTestContext());
-            final ActorRef shard = getSystem().actorOf(props);
-
-            new Within(duration("10 seconds")) {
-                @Override
-                protected void run() {
-                    shard.tell(new UpdateSchemaContext(schemaContext), getRef());
-
-
-                    // Wait for a specific log message to show up
-                    final boolean result =
-                        new JavaTestKit.EventFilter<Boolean>(Logging.Info.class
-                        ) {
-                            @Override
-                            protected Boolean run() {
-                                return true;
-                            }
-                        }.from(shard.path().toString())
-                            .message("Switching from state Candidate to Leader")
-                            .occurrences(1).exec();
-
-                    assertEquals(true, result);
-
-                    // Create a transaction on the shard
-                    shard.tell(new CreateTransaction("txn-1", TransactionProxy.TransactionType.WRITE_ONLY.ordinal() ).toSerializable(), getRef());
-
-                    final ActorSelection transaction =
-                        new ExpectMsg<ActorSelection>(duration("3 seconds"), "CreateTransactionReply") {
-                            @Override
-                            protected ActorSelection match(Object in) {
-                                if (CreateTransactionReply.SERIALIZABLE_CLASS.equals(in.getClass())) {
-                                    CreateTransactionReply reply = CreateTransactionReply.fromSerializable(in);
-                                    return getSystem()
-                                        .actorSelection(reply
-                                            .getTransactionPath());
-                                } else {
-                                    throw noMatch();
-                                }
-                            }
-                        }.get(); // this extracts the received message
-
-                    assertNotNull(transaction);
-
-                    System.out.println("Successfully created transaction");
-
-                    // 3. Write some data
-                    transaction.tell(new WriteData(TestModel.TEST_PATH,
-                        ImmutableNodes.containerNode(TestModel.TEST_QNAME), schemaContext).toSerializable(),
-                        getRef());
-
-                    Boolean writeDone = new ExpectMsg<Boolean>(duration("3 seconds"), "WriteDataReply") {
-                        @Override
-                        protected Boolean match(Object in) {
-                            if (in.getClass().equals(WriteDataReply.SERIALIZABLE_CLASS)) {
-                                return true;
-                            } else {
-                                throw noMatch();
-                            }
-                        }
-                    }.get(); // this extracts the received message
-
-                    assertTrue(writeDone);
-
-                    System.out.println("Successfully wrote data");
-
-                    // 4. Ready the transaction for commit
-
-                    transaction.tell(new ReadyTransaction().toSerializable(), getRef());
-
-                    final ActorSelection cohort =
-                        new ExpectMsg<ActorSelection>(duration("3 seconds"), "ReadyTransactionReply") {
-                            @Override
-                            protected ActorSelection match(Object in) {
-                                if (in.getClass().equals(ReadyTransactionReply.SERIALIZABLE_CLASS)) {
-                                    ActorPath cohortPath =
-                                        ReadyTransactionReply.fromSerializable(getSystem(),in)
-                                            .getCohortPath();
-                                    return getSystem()
-                                        .actorSelection(cohortPath);
-                                } else {
-                                    throw noMatch();
-                                }
-                            }
-                        }.get(); // this extracts the received message
-
-                    assertNotNull(cohort);
-
-                    System.out.println("Successfully readied the transaction");
-
-                    // 5. PreCommit the transaction
-
-                    cohort.tell(new PreCommitTransaction().toSerializable(), getRef());
-
-                    Boolean preCommitDone =
-                        new ExpectMsg<Boolean>(duration("3 seconds"), "PreCommitTransactionReply") {
-                            @Override
-                            protected Boolean match(Object in) {
-                                if (in.getClass().equals(PreCommitTransactionReply.SERIALIZABLE_CLASS)) {
-                                    return true;
-                                } else {
-                                    throw noMatch();
-                                }
-                            }
-                        }.get(); // this extracts the received message
-
-                    assertTrue(preCommitDone);
-
-                    System.out.println("Successfully pre-committed the transaction");
-
-                    // 6. Commit the transaction
-                    cohort.tell(new CommitTransaction().toSerializable(), getRef());
-
-                    // FIXME : Add assertions that the commit worked and that the cohort and transaction actors were terminated
-
-                    System.out.println("TODO : Check Successfully committed the transaction");
-                }
-
-
-            };
-        }
-
-            private ActorRef watchActor(ActorSelection actor) {
-                Future<ActorRef> future = actor
-                    .resolveOne(FiniteDuration.apply(100, "milliseconds"));
-
-                try {
-                    ActorRef actorRef = Await.result(future,
-                        FiniteDuration.apply(100, "milliseconds"));
-
-                    watch(actorRef);
-
-                    return actorRef;
-                } catch (Exception e) {
-                    throw new RuntimeException(e);
-                }
-
-            }
-        };
-
-
-    }
-}
index 2ed11cfbda21eff65b3cb6223b671731c891ab67..c79d76203589c51126dbd281adfd7dcaf4712db4 100644 (file)
@@ -82,7 +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");
+            .executeOperation(actorRef, "messages");
 
         Assert.assertNotNull(messages);
 
index ab3ff795d3cb4a4e66e3ddd708236a8d15eec365..aaf080bdf7d8d50de4a3f31713143389994872a6 100644 (file)
@@ -66,7 +66,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");
+            .executeOperation(actorRef, "messages");
 
         assertNotNull(messages);
 
@@ -95,7 +95,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");
+            .executeOperation(actorRef, "messages");
 
         assertNotNull(messages);
 
index b39cc84ceff6943d045c7a609afcbb996e212b31..101a73782b498943acb14b0cb03be2dde5df1f87 100644 (file)
 package org.opendaylight.controller.cluster.datastore;
 
 import akka.actor.ActorRef;
+import akka.actor.DeadLetter;
 import akka.actor.Props;
 import akka.testkit.JavaTestKit;
 import org.junit.Test;
+import org.mockito.Mockito;
 import org.opendaylight.controller.cluster.datastore.messages.DataChanged;
 import org.opendaylight.controller.cluster.datastore.messages.DataChangedReply;
 import org.opendaylight.controller.cluster.datastore.messages.EnableNotification;
 import org.opendaylight.controller.md.cluster.datastore.model.CompositeModel;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
 
 public class DataChangeListenerTest extends AbstractActorTest {
 
-    private static class MockDataChangedEvent implements AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> {
-       Map<YangInstanceIdentifier,NormalizedNode<?,?>> createdData = new HashMap<>();
-       Map<YangInstanceIdentifier,NormalizedNode<?,?>> updatedData = new HashMap<>();
-       Map<YangInstanceIdentifier,NormalizedNode<?,?>> originalData = new HashMap<>();
-
-
-
-        @Override
-        public Map<YangInstanceIdentifier, NormalizedNode<?, ?>> getCreatedData() {
-            createdData.put(CompositeModel.FAMILY_PATH, CompositeModel.createFamily());
-            return createdData;
-        }
-
-        @Override
-        public Map<YangInstanceIdentifier, NormalizedNode<?, ?>> getUpdatedData() {
-            updatedData.put(CompositeModel.FAMILY_PATH, CompositeModel.createFamily());
-            return updatedData;
-
-        }
-
-        @Override
-        public Set<YangInstanceIdentifier> getRemovedPaths() {
-               Set<YangInstanceIdentifier>ids = new HashSet();
-               ids.add( CompositeModel.TEST_PATH);
-              return ids;
-        }
-
-        @Override
-        public Map<YangInstanceIdentifier, NormalizedNode<?, ?>> getOriginalData() {
-          originalData.put(CompositeModel.FAMILY_PATH, CompositeModel.createFamily());
-          return originalData;
-        }
-
-        @Override public NormalizedNode<?, ?> getOriginalSubtree() {
-
-
-          return originalData.put(CompositeModel.FAMILY_PATH, CompositeModel.createFamily());
-        }
-
-        @Override public NormalizedNode<?, ?> getUpdatedSubtree() {
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Test
+    public void testDataChangedWhenNotificationsAreEnabled(){
+        new JavaTestKit(getSystem()) {{
+            final AsyncDataChangeEvent mockChangeEvent = Mockito.mock(AsyncDataChangeEvent.class);
+            final AsyncDataChangeListener mockListener = Mockito.mock(AsyncDataChangeListener.class);
+            final Props props = DataChangeListener.props(mockListener);
+            final ActorRef subject = getSystem().actorOf(props, "testDataChangedNotificationsEnabled");
 
-          //fixme: need to have some valid data here
-          return originalData.put(CompositeModel.FAMILY_PATH, CompositeModel.createFamily());
-        }
-    }
+            // Let the DataChangeListener know that notifications should be enabled
+            subject.tell(new EnableNotification(true), getRef());
 
-    private class MockDataChangeListener implements AsyncDataChangeListener<YangInstanceIdentifier, NormalizedNode<?, ?>> {
-        private boolean gotIt = false;
-        private   AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> change;
+            subject.tell(new DataChanged(CompositeModel.createTestContext(), mockChangeEvent),
+                    getRef());
 
-        @Override public void onDataChanged(
-            AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> change) {
-            gotIt = true;this.change=change;
-        }
+            expectMsgClass(DataChangedReply.class);
 
-        public boolean gotIt() {
-            return gotIt;
-        }
-        public  AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> getChange(){
-          return change;
-        }
+            Mockito.verify(mockListener).onDataChanged(mockChangeEvent);
+        }};
     }
 
+    @SuppressWarnings({ "rawtypes", "unchecked" })
     @Test
-    public void testDataChangedWhenNotificationsAreEnabled(){
+    public void testDataChangedWhenNotificationsAreDisabled(){
         new JavaTestKit(getSystem()) {{
-            final MockDataChangeListener listener = new MockDataChangeListener();
-            final Props props = DataChangeListener.props(listener);
+            final AsyncDataChangeEvent mockChangeEvent = Mockito.mock(AsyncDataChangeEvent.class);
+            final AsyncDataChangeListener mockListener = Mockito.mock(AsyncDataChangeListener.class);
+            final Props props = DataChangeListener.props(mockListener);
             final ActorRef subject =
-                getSystem().actorOf(props, "testDataChangedNotificationsEnabled");
+                getSystem().actorOf(props, "testDataChangedNotificationsDisabled");
+
+            subject.tell(new DataChanged(CompositeModel.createTestContext(), mockChangeEvent),
+                    getRef());
 
             new Within(duration("1 seconds")) {
                 @Override
                 protected void run() {
-
-                    // Let the DataChangeListener know that notifications should
-                    // be enabled
-                    subject.tell(new EnableNotification(true), getRef());
-
-                    subject.tell(
-                        new DataChanged(CompositeModel.createTestContext(),new MockDataChangedEvent()),
-                        getRef());
-
-                    final Boolean out = new ExpectMsg<Boolean>(duration("800 millis"), "dataChanged") {
-                        // do not put code outside this method, will run afterwards
-                        @Override
-                        protected Boolean match(Object in) {
-                            if (in != null && in.getClass().equals(DataChangedReply.class)) {
-
-                                return true;
-                            } else {
-                                throw noMatch();
-                            }
-                        }
-                    }.get(); // this extracts the received message
-
-                    assertTrue(out);
-                    assertTrue(listener.gotIt());
-                    assertNotNull(listener.getChange().getCreatedData());
-
                     expectNoMsg();
+
+                    Mockito.verify(mockListener, Mockito.never()).onDataChanged(
+                            Mockito.any(AsyncDataChangeEvent.class));
                 }
             };
         }};
     }
 
+    @SuppressWarnings({ "rawtypes", "unchecked" })
     @Test
-    public void testDataChangedWhenNotificationsAreDisabled(){
+    public void testDataChangedWithNoSender(){
         new JavaTestKit(getSystem()) {{
-            final MockDataChangeListener listener = new MockDataChangeListener();
-            final Props props = DataChangeListener.props(listener);
-            final ActorRef subject =
-                getSystem().actorOf(props, "testDataChangedNotificationsDisabled");
+            final AsyncDataChangeEvent mockChangeEvent = Mockito.mock(AsyncDataChangeEvent.class);
+            final AsyncDataChangeListener mockListener = Mockito.mock(AsyncDataChangeListener.class);
+            final Props props = DataChangeListener.props(mockListener);
+            final ActorRef subject = getSystem().actorOf(props, "testDataChangedWithNoSender");
 
+            // Let the DataChangeListener know that notifications should be enabled
+            subject.tell(new EnableNotification(true), ActorRef.noSender());
+
+            subject.tell(new DataChanged(CompositeModel.createTestContext(), mockChangeEvent),
+                    ActorRef.noSender());
+
+            getSystem().eventStream().subscribe(getRef(), DeadLetter.class);
             new Within(duration("1 seconds")) {
                 @Override
                 protected void run() {
-
-                    subject.tell(
-                        new DataChanged(CompositeModel.createTestContext(),new MockDataChangedEvent()),
-                        getRef());
-
                     expectNoMsg();
                 }
             };
index ec8aee2b09d4dfaf4ed4b5b732a9168783beb73c..395021d361c6d4b210fcf29bf20707802b6c590a 100644 (file)
@@ -1,17 +1,12 @@
 package org.opendaylight.controller.cluster.datastore;
 
+import akka.actor.ActorRef;
 import akka.actor.ActorSystem;
-import akka.event.Logging;
-import akka.testkit.JavaTestKit;
-
+import akka.actor.PoisonPill;
 import com.google.common.base.Optional;
-import com.google.common.util.concurrent.ListenableFuture;
-
-import junit.framework.Assert;
-
-import org.apache.commons.io.FileUtils;
-import org.junit.After;
-import org.junit.Before;
+import com.google.common.util.concurrent.Uninterruptibles;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import org.junit.Test;
 import org.opendaylight.controller.cluster.datastore.shardstrategy.ShardStrategyFactory;
 import org.opendaylight.controller.cluster.datastore.utils.MockClusterWrapper;
@@ -19,292 +14,268 @@ import org.opendaylight.controller.md.cluster.datastore.model.CarsModel;
 import org.opendaylight.controller.md.cluster.datastore.model.PeopleModel;
 import org.opendaylight.controller.md.cluster.datastore.model.SchemaContextHelper;
 import org.opendaylight.controller.md.cluster.datastore.model.TestModel;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.concurrent.ExecutionException;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
 
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertTrue;
-import static junit.framework.Assert.fail;
+public class DistributedDataStoreIntegrationTest extends AbstractActorTest {
 
-public class DistributedDataStoreIntegrationTest {
+    @Test
+    public void testWriteTransactionWithSingleShard() throws Exception{
+        System.setProperty("shard.persistent", "true");
+        new IntegrationTestKit(getSystem()) {{
+            DistributedDataStore dataStore =
+                    setupDistributedDataStore("transactionIntegrationTest", "test-1");
 
-    private static ActorSystem system;
+            testWriteTransaction(dataStore, TestModel.TEST_PATH,
+                    ImmutableNodes.containerNode(TestModel.TEST_QNAME));
 
-    @Before
-    public void setUp() throws IOException {
-        File journal = new File("journal");
+            testWriteTransaction(dataStore, TestModel.OUTER_LIST_PATH,
+                    ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME).build());
 
-        if(journal.exists()) {
-            FileUtils.deleteDirectory(journal);
-        }
+            cleanup(dataStore);
+        }};
+    }
 
+    @Test
+    public void testWriteTransactionWithMultipleShards() throws Exception{
+        System.setProperty("shard.persistent", "true");
+        new IntegrationTestKit(getSystem()) {{
+            DistributedDataStore dataStore =
+                    setupDistributedDataStore("testWriteTransactionWithMultipleShards", "cars-1", "people-1");
 
-        System.setProperty("shard.persistent", "false");
-        system = ActorSystem.create("test");
-    }
+            DOMStoreWriteTransaction writeTx = dataStore.newWriteOnlyTransaction();
+            assertNotNull("newWriteOnlyTransaction returned null", writeTx);
 
-    @After
-    public void tearDown() {
-        JavaTestKit.shutdownActorSystem(system);
-        system = null;
-    }
+            YangInstanceIdentifier nodePath1 = CarsModel.BASE_PATH;
+            NormalizedNode<?, ?> nodeToWrite1 = CarsModel.emptyContainer();
+            writeTx.write(nodePath1, nodeToWrite1);
 
-    protected ActorSystem getSystem() {
-        return system;
-    }
+            YangInstanceIdentifier nodePath2 = PeopleModel.BASE_PATH;
+            NormalizedNode<?, ?> nodeToWrite2 = PeopleModel.emptyContainer();
+            writeTx.write(nodePath2, nodeToWrite2);
 
-    @Test
-    public void integrationTest() throws Exception {
-        final Configuration configuration = new ConfigurationImpl("module-shards.conf", "modules.conf");
-        ShardStrategyFactory.setConfiguration(configuration);
+            DOMStoreThreePhaseCommitCohort cohort = writeTx.ready();
 
+            Boolean canCommit = cohort.canCommit().get(5, TimeUnit.SECONDS);
+            assertEquals("canCommit", true, canCommit);
+            cohort.preCommit().get(5, TimeUnit.SECONDS);
+            cohort.commit().get(5, TimeUnit.SECONDS);
 
+            // 5. Verify the data in the store
 
-        new JavaTestKit(getSystem()) {
-            {
+            DOMStoreReadTransaction readTx = dataStore.newReadOnlyTransaction();
 
-                new Within(duration("10 seconds")) {
-                    @Override
-                    protected void run() {
-                        try {
-                            final DistributedDataStore distributedDataStore =
-                                new DistributedDataStore(getSystem(), "config",
-                                        new MockClusterWrapper(), configuration,
-                                        new DatastoreContext());
+            Optional<NormalizedNode<?, ?>> optional = readTx.read(nodePath1).get();
+            assertEquals("isPresent", true, optional.isPresent());
+            assertEquals("Data node", nodeToWrite1, optional.get());
 
-                            distributedDataStore.onGlobalContextUpdated(TestModel.createTestContext());
+            optional = readTx.read(nodePath2).get();
+            assertEquals("isPresent", true, optional.isPresent());
+            assertEquals("Data node", nodeToWrite2, optional.get());
 
-                            // Wait for a specific log message to show up
-                            final boolean result =
-                                new JavaTestKit.EventFilter<Boolean>(Logging.Info.class
-                                    ) {
-                                    @Override
-                                    protected Boolean run() {
-                                        return true;
-                                    }
-                                }.from("akka://test/user/shardmanager-config/member-1-shard-test-1-config")
-                                    .message("Switching from state Candidate to Leader")
-                                    .occurrences(1).exec();
+            cleanup(dataStore);
+        }};
+    }
 
-                            assertEquals(true, result);
+    @Test
+    public void testReadWriteTransaction() throws Exception{
+        System.setProperty("shard.persistent", "true");
+        new IntegrationTestKit(getSystem()) {{
+            DistributedDataStore dataStore =
+                    setupDistributedDataStore("testReadWriteTransaction", "test-1");
 
-                            DOMStoreReadWriteTransaction transaction =
-                                distributedDataStore.newReadWriteTransaction();
+         // 1. Create a read-write Tx
 
-                            transaction
-                                .write(TestModel.TEST_PATH, ImmutableNodes
-                                    .containerNode(TestModel.TEST_QNAME));
+            DOMStoreReadWriteTransaction readWriteTx = dataStore.newReadWriteTransaction();
+            assertNotNull("newReadWriteTransaction returned null", readWriteTx);
 
-                            ListenableFuture<Optional<NormalizedNode<?, ?>>>
-                                future =
-                                transaction.read(TestModel.TEST_PATH);
+            // 2. Write some data
 
-                            Optional<NormalizedNode<?, ?>> optional =
-                                future.get();
+            YangInstanceIdentifier nodePath = TestModel.TEST_PATH;
+            NormalizedNode<?, ?> nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
+            readWriteTx.write(nodePath, nodeToWrite );
 
-                            Assert.assertTrue("Node not found", optional.isPresent());
+            // 3. Read the data from Tx
 
-                            NormalizedNode<?, ?> normalizedNode =
-                                optional.get();
+            Boolean exists = readWriteTx.exists(nodePath).checkedGet(5, TimeUnit.SECONDS);
+            assertEquals("exists", true, exists);
 
-                            assertEquals(TestModel.TEST_QNAME,
-                                normalizedNode.getNodeType());
+            Optional<NormalizedNode<?, ?>> optional = readWriteTx.read(nodePath).get(5, TimeUnit.SECONDS);
+            assertEquals("isPresent", true, optional.isPresent());
+            assertEquals("Data node", nodeToWrite, optional.get());
 
-                            DOMStoreThreePhaseCommitCohort ready =
-                                transaction.ready();
+            // 4. Ready the Tx for commit
 
-                            ListenableFuture<Boolean> canCommit =
-                                ready.canCommit();
+            DOMStoreThreePhaseCommitCohort cohort = readWriteTx.ready();
 
-                            assertTrue(canCommit.get(5, TimeUnit.SECONDS));
+            // 5. Commit the Tx
 
-                            ListenableFuture<Void> preCommit =
-                                ready.preCommit();
+            Boolean canCommit = cohort.canCommit().get(5, TimeUnit.SECONDS);
+            assertEquals("canCommit", true, canCommit);
+            cohort.preCommit().get(5, TimeUnit.SECONDS);
+            cohort.commit().get(5, TimeUnit.SECONDS);
 
-                            preCommit.get(5, TimeUnit.SECONDS);
+            // 6. Verify the data in the store
 
-                            ListenableFuture<Void> commit = ready.commit();
+            DOMStoreReadTransaction readTx = dataStore.newReadOnlyTransaction();
 
-                            commit.get(5, TimeUnit.SECONDS);
-                        } catch (ExecutionException | TimeoutException | InterruptedException e){
-                            fail(e.getMessage());
-                        }
-                    }
-                };
-            }
-        };
+            optional = readTx.read(nodePath).get(5, TimeUnit.SECONDS);
+            assertEquals("isPresent", true, optional.isPresent());
+            assertEquals("Data node", nodeToWrite, optional.get());
 
+            cleanup(dataStore);
+        }};
     }
 
     @Test
-    public void transactionChainIntegrationTest() throws Exception {
-        final Configuration configuration = new ConfigurationImpl("module-shards.conf", "modules.conf");
-        ShardStrategyFactory.setConfiguration(configuration);
+    public void testTransactionAbort() throws Exception{
+        System.setProperty("shard.persistent", "true");
+        new IntegrationTestKit(getSystem()) {{
+            DistributedDataStore dataStore =
+                    setupDistributedDataStore("transactionAbortIntegrationTest", "test-1");
 
+            DOMStoreWriteTransaction writeTx = dataStore.newWriteOnlyTransaction();
+            assertNotNull("newWriteOnlyTransaction returned null", writeTx);
 
+            writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
 
-        new JavaTestKit(getSystem()) {
-            {
+            DOMStoreThreePhaseCommitCohort cohort = writeTx.ready();
 
-                new Within(duration("10 seconds")) {
-                    @Override
-                    protected void run() {
-                        try {
-                            final DistributedDataStore distributedDataStore =
-                                new DistributedDataStore(getSystem(), "config",
-                                    new MockClusterWrapper(), configuration,
-                                    new DatastoreContext());
+            cohort.canCommit().get(5, TimeUnit.SECONDS);
 
-                            distributedDataStore.onGlobalContextUpdated(TestModel.createTestContext());
+            cohort.abort().get(5, TimeUnit.SECONDS);
 
-                            // Wait for a specific log message to show up
-                            final boolean result =
-                                new JavaTestKit.EventFilter<Boolean>(Logging.Info.class
-                                ) {
-                                    @Override
-                                    protected Boolean run() {
-                                        return true;
-                                    }
-                                }.from("akka://test/user/shardmanager-config/member-1-shard-test-1-config")
-                                    .message("Switching from state Candidate to Leader")
-                                    .occurrences(1).exec();
+            testWriteTransaction(dataStore, TestModel.TEST_PATH,
+                    ImmutableNodes.containerNode(TestModel.TEST_QNAME));
 
-                            assertEquals(true, result);
-
-                            DOMStoreTransactionChain transactionChain =
-                                distributedDataStore.createTransactionChain();
-
-                            DOMStoreReadWriteTransaction transaction =
-                                transactionChain.newReadWriteTransaction();
+            cleanup(dataStore);
+        }};
+    }
 
-                            transaction
-                                .write(TestModel.TEST_PATH, ImmutableNodes
-                                    .containerNode(TestModel.TEST_QNAME));
+    @Test
+    public void testTransactionChain() throws Exception{
+        System.setProperty("shard.persistent", "true");
+        new IntegrationTestKit(getSystem()) {{
+            DistributedDataStore dataStore =
+                    setupDistributedDataStore("transactionChainIntegrationTest", "test-1");
 
-                            ListenableFuture<Optional<NormalizedNode<?, ?>>>
-                                future =
-                                transaction.read(TestModel.TEST_PATH);
+            // 1. Create a Tx chain and write-only Tx
 
-                            Optional<NormalizedNode<?, ?>> optional =
-                                future.get();
+            DOMStoreTransactionChain txChain = dataStore.createTransactionChain();
 
-                            Assert.assertTrue("Node not found", optional.isPresent());
+            DOMStoreWriteTransaction writeTx = txChain.newWriteOnlyTransaction();
+            assertNotNull("newWriteOnlyTransaction returned null", writeTx);
 
-                            NormalizedNode<?, ?> normalizedNode =
-                                optional.get();
+            // 2. Write some data
 
-                            assertEquals(TestModel.TEST_QNAME,
-                                normalizedNode.getNodeType());
+            NormalizedNode<?, ?> containerNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
+            writeTx.write(TestModel.TEST_PATH, containerNode);
 
-                            DOMStoreThreePhaseCommitCohort ready =
-                                transaction.ready();
+            // 3. Ready the Tx for commit
 
-                            ListenableFuture<Boolean> canCommit =
-                                ready.canCommit();
+            DOMStoreThreePhaseCommitCohort cohort = writeTx.ready();
 
-                            assertTrue(canCommit.get(5, TimeUnit.SECONDS));
+            // 4. Commit the Tx
 
-                            ListenableFuture<Void> preCommit =
-                                ready.preCommit();
+            Boolean canCommit = cohort.canCommit().get(5, TimeUnit.SECONDS);
+            assertEquals("canCommit", true, canCommit);
+            cohort.preCommit().get(5, TimeUnit.SECONDS);
+            cohort.commit().get(5, TimeUnit.SECONDS);
 
-                            preCommit.get(5, TimeUnit.SECONDS);
+            // 5. Verify the data in the store
 
-                            ListenableFuture<Void> commit = ready.commit();
+            DOMStoreReadTransaction readTx = txChain.newReadOnlyTransaction();
 
-                            commit.get(5, TimeUnit.SECONDS);
+            Optional<NormalizedNode<?, ?>> optional = readTx.read(TestModel.TEST_PATH).get(5, TimeUnit.SECONDS);
+            assertEquals("isPresent", true, optional.isPresent());
+            assertEquals("Data node", containerNode, optional.get());
 
-                            transactionChain.close();
-                        } catch (ExecutionException | TimeoutException | InterruptedException e){
-                            fail(e.getMessage());
-                        }
-                    }
-                };
-            }
-        };
+            txChain.close();
 
+            cleanup(dataStore);
+        }};
     }
 
+    class IntegrationTestKit extends ShardTestKit {
 
-    //FIXME : Disabling test because it's flaky
-    //@Test
-    public void integrationTestWithMultiShardConfiguration()
-        throws ExecutionException, InterruptedException, TimeoutException {
-        final Configuration configuration = new ConfigurationImpl("module-shards.conf", "modules.conf");
-
-        ShardStrategyFactory.setConfiguration(configuration);
-
-        new JavaTestKit(getSystem()) {
-            {
+        IntegrationTestKit(ActorSystem actorSystem) {
+            super(actorSystem);
+        }
 
-                new Within(duration("10 seconds")) {
-                    @Override
-                    protected void run() {
-                        try {
-                            final DistributedDataStore distributedDataStore =
-                                new DistributedDataStore(getSystem(), "config",
-                                    new MockClusterWrapper(), configuration, null);
+        DistributedDataStore setupDistributedDataStore(String typeName, String... shardNames) {
+            MockClusterWrapper cluster = new MockClusterWrapper();
+            Configuration config = new ConfigurationImpl("module-shards.conf", "modules.conf");
+            ShardStrategyFactory.setConfiguration(config);
+
+            DatastoreContext datastoreContext = DatastoreContext.newBuilder().build();
+            DistributedDataStore dataStore = new DistributedDataStore(getSystem(), typeName, cluster,
+                    config, datastoreContext);
+
+            SchemaContext schemaContext = SchemaContextHelper.full();
+            dataStore.onGlobalContextUpdated(schemaContext);
+
+            for(String shardName: shardNames) {
+                ActorRef shard = null;
+                for(int i = 0; i < 20 * 5 && shard == null; i++) {
+                    Uninterruptibles.sleepUninterruptibly(50, TimeUnit.MILLISECONDS);
+                    Optional<ActorRef> shardReply = dataStore.getActorContext().findLocalShard(shardName);
+                    if(shardReply.isPresent()) {
+                        shard = shardReply.get();
+                    }
+                }
 
-                            distributedDataStore.onGlobalContextUpdated(
-                                SchemaContextHelper.full());
+                assertNotNull("Shard was not created", shard);
 
-                            // Wait for a specific log message to show up
-                            final boolean result =
-                                new JavaTestKit.EventFilter<Boolean>(
-                                    Logging.Info.class
-                                ) {
-                                    @Override
-                                    protected Boolean run() {
-                                        return true;
-                                    }
-                                }.from(
-                                    "akka://test/user/shardmanager-config/member-1-shard-cars-1-config")
-                                    .message(
-                                        "Switching from state Candidate to Leader")
-                                    .occurrences(1)
-                                    .exec();
+                System.out.println("!!!!!!shard: "+shard.path().toString());
+                waitUntilLeader(shard);
+            }
 
-                            Thread.sleep(1000);
+            return dataStore;
+        }
 
+        void testWriteTransaction(DistributedDataStore dataStore, YangInstanceIdentifier nodePath,
+                NormalizedNode<?, ?> nodeToWrite) throws Exception {
 
-                            DOMStoreReadWriteTransaction transaction =
-                                distributedDataStore.newReadWriteTransaction();
+            // 1. Create a write-only Tx
 
-                            transaction.write(CarsModel.BASE_PATH, CarsModel.emptyContainer());
-                            transaction.write(PeopleModel.BASE_PATH, PeopleModel.emptyContainer());
+            DOMStoreWriteTransaction writeTx = dataStore.newWriteOnlyTransaction();
+            assertNotNull("newWriteOnlyTransaction returned null", writeTx);
 
-                            DOMStoreThreePhaseCommitCohort ready = transaction.ready();
+            // 2. Write some data
 
-                            ListenableFuture<Boolean> canCommit = ready.canCommit();
+            writeTx.write(nodePath, nodeToWrite);
 
-                            assertTrue(canCommit.get(5, TimeUnit.SECONDS));
+            // 3. Ready the Tx for commit
 
-                            ListenableFuture<Void> preCommit = ready.preCommit();
+            DOMStoreThreePhaseCommitCohort cohort = writeTx.ready();
 
-                            preCommit.get(5, TimeUnit.SECONDS);
+            // 4. Commit the Tx
 
-                            ListenableFuture<Void> commit = ready.commit();
+            Boolean canCommit = cohort.canCommit().get(5, TimeUnit.SECONDS);
+            assertEquals("canCommit", true, canCommit);
+            cohort.preCommit().get(5, TimeUnit.SECONDS);
+            cohort.commit().get(5, TimeUnit.SECONDS);
 
-                            commit.get(5, TimeUnit.SECONDS);
+            // 5. Verify the data in the store
 
-                            assertEquals(true, result);
-                        } catch(ExecutionException | TimeoutException | InterruptedException e){
-                            fail(e.getMessage());
-                        }
-                    }
-                };
-            }
-        };
+            DOMStoreReadTransaction readTx = dataStore.newReadOnlyTransaction();
 
+            Optional<NormalizedNode<?, ?>> optional = readTx.read(nodePath).get(5, TimeUnit.SECONDS);
+            assertEquals("isPresent", true, optional.isPresent());
+            assertEquals("Data node", nodeToWrite, optional.get());
+        }
 
+        void cleanup(DistributedDataStore dataStore) {
+            dataStore.getActorContext().getShardManager().tell(PoisonPill.getInstance(), null);
+        }
     }
 
 }
index 08c3ea9602adb9cd891f9e1fe573ded671e5d6d7..00243ea5d1d1e9e52cff5dfc21335d7a5cbdc13f 100644 (file)
@@ -8,6 +8,7 @@ import akka.actor.Props;
 import akka.dispatch.ExecutionContexts;
 import akka.dispatch.Futures;
 import akka.util.Timeout;
+import com.google.common.base.Optional;
 import com.google.common.util.concurrent.MoreExecutors;
 import org.junit.After;
 import org.junit.Before;
@@ -33,9 +34,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import scala.concurrent.ExecutionContextExecutor;
 import scala.concurrent.Future;
 import scala.concurrent.duration.FiniteDuration;
-
 import java.util.concurrent.TimeUnit;
-
 import static junit.framework.TestCase.assertEquals;
 import static junit.framework.TestCase.assertNull;
 import static org.junit.Assert.assertNotNull;
@@ -87,7 +86,7 @@ public class DistributedDataStoreTest extends AbstractActorTest{
 
         new DistributedDataStore(actorSystem, "config",
             mock(ClusterWrapper.class), mock(Configuration.class),
-            new DatastoreContext());
+            DatastoreContext.newBuilder().build());
 
         verify(actorSystem).actorOf(any(Props.class), eq("shardmanager-config"));
     }
@@ -97,11 +96,11 @@ public class DistributedDataStoreTest extends AbstractActorTest{
 
         ListenerRegistration registration =
                 distributedDataStore.registerChangeListener(TestModel.TEST_PATH, new AsyncDataChangeListener<YangInstanceIdentifier, NormalizedNode<?, ?>>() {
-            @Override
-            public void onDataChanged(AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> change) {
-                throw new UnsupportedOperationException("onDataChanged");
-            }
-        }, AsyncDataBroker.DataChangeScope.BASE);
+                    @Override
+                    public void onDataChanged(AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> change) {
+                        throw new UnsupportedOperationException("onDataChanged");
+                    }
+                }, AsyncDataBroker.DataChangeScope.BASE);
 
         // Since we do not expect the shard to be local registration will return a NoOpRegistration
         assertTrue(registration instanceof NoOpDataChangeListenerRegistration);
@@ -119,8 +118,9 @@ public class DistributedDataStoreTest extends AbstractActorTest{
         Future future = mock(Future.class);
         when(actorContext.getOperationDuration()).thenReturn(FiniteDuration.apply(5, TimeUnit.SECONDS));
         when(actorContext.getActorSystem()).thenReturn(getSystem());
+        when(actorContext.findLocalShard(anyString())).thenReturn(Optional.of(doNothingActorRef));
         when(actorContext
-            .executeLocalShardOperationAsync(anyString(), anyObject(), any(Timeout.class))).thenReturn(future);
+                .executeOperationAsync(eq(doNothingActorRef), anyObject(), any(Timeout.class))).thenReturn(future);
 
         ListenerRegistration registration =
             distributedDataStore.registerChangeListener(TestModel.TEST_PATH,
@@ -153,8 +153,9 @@ public class DistributedDataStoreTest extends AbstractActorTest{
         when(actorSystem.dispatcher()).thenReturn(executor);
         when(actorSystem.actorOf(any(Props.class))).thenReturn(doNothingActorRef);
         when(actorContext.getActorSystem()).thenReturn(actorSystem);
+        when(actorContext.findLocalShard(anyString())).thenReturn(Optional.of(doNothingActorRef));
         when(actorContext
-            .executeLocalShardOperationAsync(anyString(), anyObject(), any(Timeout.class))).thenReturn(f);
+            .executeOperationAsync(eq(doNothingActorRef), anyObject(), any(Timeout.class))).thenReturn(f);
         when(actorContext.actorSelection(any(ActorPath.class))).thenReturn(actorSelection);
 
         ListenerRegistration registration =
@@ -195,8 +196,9 @@ public class DistributedDataStoreTest extends AbstractActorTest{
         when(actorSystem.dispatcher()).thenReturn(executor);
         when(actorSystem.actorOf(any(Props.class))).thenReturn(doNothingActorRef);
         when(actorContext.getActorSystem()).thenReturn(actorSystem);
+        when(actorContext.findLocalShard(anyString())).thenReturn(Optional.of(doNothingActorRef));
         when(actorContext
-            .executeLocalShardOperationAsync(anyString(), anyObject(), any(Timeout.class))).thenReturn(f);
+            .executeOperationAsync(eq(doNothingActorRef), anyObject(), any(Timeout.class))).thenReturn(f);
         when(actorContext.actorSelection(any(ActorPath.class))).thenReturn(actorSelection);
 
         ListenerRegistration registration =
index 8a3cdd0c8aa3b9890811c8a52318c8c18051d7b8..5022d97997dfad32ef29ae16865a7e7dc3c2b6e1 100644 (file)
@@ -1,27 +1,20 @@
 package org.opendaylight.controller.cluster.datastore;
 
 import akka.actor.ActorRef;
-import akka.actor.ActorSystem;
 import akka.actor.Props;
-import akka.dispatch.Futures;
-import akka.japi.Procedure;
-import akka.persistence.PersistentConfirmation;
-import akka.persistence.PersistentId;
-import akka.persistence.PersistentImpl;
-import akka.persistence.PersistentRepr;
-import akka.persistence.journal.japi.AsyncWriteJournal;
+import akka.persistence.RecoveryCompleted;
 import akka.testkit.JavaTestKit;
 import akka.testkit.TestActorRef;
+import akka.japi.Creator;
 import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
 import com.google.common.util.concurrent.Uninterruptibles;
-import com.typesafe.config.Config;
-import com.typesafe.config.ConfigFactory;
-import com.typesafe.config.ConfigValueFactory;
-import org.junit.AfterClass;
+import org.junit.After;
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
+import org.opendaylight.controller.cluster.datastore.identifiers.ShardIdentifier;
+import org.opendaylight.controller.cluster.datastore.messages.ActorInitialized;
+import org.opendaylight.controller.cluster.datastore.messages.ActorNotInitialized;
 import org.opendaylight.controller.cluster.datastore.messages.FindLocalShard;
 import org.opendaylight.controller.cluster.datastore.messages.FindPrimary;
 import org.opendaylight.controller.cluster.datastore.messages.LocalShardFound;
@@ -29,306 +22,258 @@ import org.opendaylight.controller.cluster.datastore.messages.LocalShardNotFound
 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.DoNothingActor;
+import org.opendaylight.controller.cluster.datastore.utils.InMemoryJournal;
 import org.opendaylight.controller.cluster.datastore.utils.MockClusterWrapper;
 import org.opendaylight.controller.cluster.datastore.utils.MockConfiguration;
 import org.opendaylight.controller.md.cluster.datastore.model.TestModel;
 import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import scala.concurrent.Future;
-
 import java.net.URI;
 import java.util.Collection;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
-
-import static junit.framework.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-public class ShardManagerTest {
-    private static ActorSystem system;
+public class ShardManagerTest extends AbstractActorTest {
+    private static int ID_COUNTER = 1;
 
-    @BeforeClass
-    public static void setUpClass() {
-        Map<String, String> myJournal = new HashMap<>();
-        myJournal.put("class", "org.opendaylight.controller.cluster.datastore.ShardManagerTest$MyJournal");
-        myJournal.put("plugin-dispatcher", "akka.actor.default-dispatcher");
-        Config config = ConfigFactory.load()
-            .withValue("akka.persistence.journal.plugin",
-                ConfigValueFactory.fromAnyRef("my-journal"))
-            .withValue("my-journal", ConfigValueFactory.fromMap(myJournal));
+    private final String shardMrgIDSuffix = "config" + ID_COUNTER++;
+    private final String shardMgrID = "shard-manager-" + shardMrgIDSuffix;
 
-        MyJournal.clear();
+    private static ActorRef mockShardActor;
+
+    @Before
+    public void setUp() {
+        InMemoryJournal.clear();
 
-        system = ActorSystem.create("test", config);
+        if(mockShardActor == null) {
+            String name = new ShardIdentifier(Shard.DEFAULT_NAME, "member-1","config").toString();
+            mockShardActor = getSystem().actorOf(Props.create(DoNothingActor.class), name);
+        }
     }
 
-    @AfterClass
-    public static void tearDown() {
-        JavaTestKit.shutdownActorSystem(system);
-        system = null;
+    @After
+    public void tearDown() {
+        InMemoryJournal.clear();
     }
 
-    @Before
-    public void setUpTest(){
-        MyJournal.clear();
+    private Props newShardMgrProps() {
+        return ShardManager.props(shardMrgIDSuffix, new MockClusterWrapper(), new MockConfiguration(),
+                DatastoreContext.newBuilder().build());
     }
 
     @Test
     public void testOnReceiveFindPrimaryForNonExistentShard() throws Exception {
+        new JavaTestKit(getSystem()) {{
+            final ActorRef shardManager = getSystem().actorOf(newShardMgrProps());
 
-        new JavaTestKit(system) {
-            {
-                final Props props = ShardManager
-                    .props("config", new MockClusterWrapper(),
-                        new MockConfiguration(), new DatastoreContext());
+            shardManager.tell(new UpdateSchemaContext(TestModel.createTestContext()), getRef());
 
-                final ActorRef subject = getSystem().actorOf(props);
+            shardManager.tell(new FindPrimary("non-existent").toSerializable(), getRef());
 
-                subject.tell(new FindPrimary("inventory").toSerializable(), getRef());
-
-                expectMsgEquals(duration("2 seconds"),
-                    new PrimaryNotFound("inventory").toSerializable());
-            }};
+            expectMsgEquals(duration("5 seconds"),
+                    new PrimaryNotFound("non-existent").toSerializable());
+        }};
     }
 
     @Test
     public void testOnReceiveFindPrimaryForExistentShard() throws Exception {
+        new JavaTestKit(getSystem()) {{
+            final ActorRef shardManager = getSystem().actorOf(newShardMgrProps());
 
-        new JavaTestKit(system) {{
-            final Props props = ShardManager
-                .props("config", new MockClusterWrapper(),
-                    new MockConfiguration(), new DatastoreContext());
+            shardManager.tell(new UpdateSchemaContext(TestModel.createTestContext()), getRef());
+            shardManager.tell(new ActorInitialized(), mockShardActor);
 
-            final ActorRef subject = getSystem().actorOf(props);
+            shardManager.tell(new FindPrimary(Shard.DEFAULT_NAME).toSerializable(), getRef());
 
-            subject.tell(new UpdateSchemaContext(TestModel.createTestContext()), getRef());
+            expectMsgClass(duration("5 seconds"), PrimaryFound.SERIALIZABLE_CLASS);
+        }};
+    }
+
+    @Test
+    public void testOnReceiveFindPrimaryForNotInitialzedShard() throws Exception {
+        new JavaTestKit(getSystem()) {{
+            final ActorRef shardManager = getSystem().actorOf(newShardMgrProps());
 
-            subject.tell(new FindPrimary(Shard.DEFAULT_NAME).toSerializable(), getRef());
+            shardManager.tell(new UpdateSchemaContext(TestModel.createTestContext()), getRef());
 
-            expectMsgClass(duration("1 seconds"), PrimaryFound.SERIALIZABLE_CLASS);
+            shardManager.tell(new FindPrimary(Shard.DEFAULT_NAME).toSerializable(), getRef());
+
+            expectMsgClass(duration("5 seconds"), ActorNotInitialized.class);
         }};
     }
 
     @Test
     public void testOnReceiveFindLocalShardForNonExistentShard() throws Exception {
+        new JavaTestKit(getSystem()) {{
+            final ActorRef shardManager = getSystem().actorOf(newShardMgrProps());
 
-        new JavaTestKit(system) {{
-            final Props props = ShardManager
-                .props("config", new MockClusterWrapper(),
-                    new MockConfiguration(), new DatastoreContext());
-
-            final ActorRef subject = getSystem().actorOf(props);
+            shardManager.tell(new UpdateSchemaContext(TestModel.createTestContext()), getRef());
 
-            subject.tell(new FindLocalShard("inventory"), getRef());
+            shardManager.tell(new FindLocalShard("non-existent"), getRef());
 
-            final String out = new ExpectMsg<String>(duration("3 seconds"), "find local") {
-                @Override
-                protected String match(Object in) {
-                    if (in instanceof LocalShardNotFound) {
-                        return ((LocalShardNotFound) in).getShardName();
-                    } else {
-                        throw noMatch();
-                    }
-                }
-            }.get(); // this extracts the received message
+            LocalShardNotFound notFound = expectMsgClass(duration("5 seconds"), LocalShardNotFound.class);
 
-            assertEquals("inventory", out);
+            assertEquals("getShardName", "non-existent", notFound.getShardName());
         }};
     }
 
     @Test
     public void testOnReceiveFindLocalShardForExistentShard() throws Exception {
+        new JavaTestKit(getSystem()) {{
+            final ActorRef shardManager = getSystem().actorOf(newShardMgrProps());
 
-        final MockClusterWrapper mockClusterWrapper = new MockClusterWrapper();
+            shardManager.tell(new UpdateSchemaContext(TestModel.createTestContext()), getRef());
+            shardManager.tell(new ActorInitialized(), mockShardActor);
 
-        new JavaTestKit(system) {{
-            final Props props = ShardManager
-                .props("config", mockClusterWrapper,
-                    new MockConfiguration(), new DatastoreContext());
+            shardManager.tell(new FindLocalShard(Shard.DEFAULT_NAME), getRef());
 
-            final ActorRef subject = getSystem().actorOf(props);
+            LocalShardFound found = expectMsgClass(duration("5 seconds"), LocalShardFound.class);
 
-            subject.tell(new UpdateSchemaContext(TestModel.createTestContext()), getRef());
+            assertTrue("Found path contains " + found.getPath().path().toString(),
+                    found.getPath().path().toString().contains("member-1-shard-default-config"));
+        }};
+    }
+
+    @Test
+    public void testOnReceiveFindLocalShardForNotInitializedShard() throws Exception {
+        new JavaTestKit(getSystem()) {{
+            final ActorRef shardManager = getSystem().actorOf(newShardMgrProps());
 
-            subject.tell(new FindLocalShard(Shard.DEFAULT_NAME), getRef());
+            shardManager.tell(new UpdateSchemaContext(TestModel.createTestContext()), getRef());
+            //shardManager.tell(new ActorInitialized(), mockShardActor);
 
-            final ActorRef out = new ExpectMsg<ActorRef>(duration("3 seconds"), "find local") {
-                @Override
-                protected ActorRef match(Object in) {
-                    if (in instanceof LocalShardFound) {
-                        return ((LocalShardFound) in).getPath();
-                    } else {
-                        throw noMatch();
-                    }
-                }
-            }.get(); // this extracts the received message
+            shardManager.tell(new FindLocalShard(Shard.DEFAULT_NAME), getRef());
 
-            assertTrue(out.path().toString(),
-                out.path().toString().contains("member-1-shard-default-config"));
+            expectMsgClass(duration("5 seconds"), ActorNotInitialized.class);
         }};
     }
 
     @Test
     public void testOnReceiveMemberUp() throws Exception {
+        new JavaTestKit(getSystem()) {{
+            final ActorRef shardManager = getSystem().actorOf(newShardMgrProps());
 
-        new JavaTestKit(system) {{
-            final Props props = ShardManager
-                .props("config", new MockClusterWrapper(),
-                    new MockConfiguration(), new DatastoreContext());
+            MockClusterWrapper.sendMemberUp(shardManager, "member-2", getRef().path().toString());
 
-            final ActorRef subject = getSystem().actorOf(props);
-
-            MockClusterWrapper.sendMemberUp(subject, "member-2", getRef().path().toString());
-
-            subject.tell(new FindPrimary("astronauts").toSerializable(), getRef());
-
-            final String out = new ExpectMsg<String>(duration("3 seconds"), "primary found") {
-                // do not put code outside this method, will run afterwards
-                @Override
-                protected String match(Object in) {
-                    if (in.getClass().equals(PrimaryFound.SERIALIZABLE_CLASS)) {
-                        PrimaryFound f = PrimaryFound.fromSerializable(in);
-                        return f.getPrimaryPath();
-                    } else {
-                        throw noMatch();
-                    }
-                }
-            }.get(); // this extracts the received message
+            shardManager.tell(new FindPrimary("astronauts").toSerializable(), getRef());
 
-            assertTrue(out, out.contains("member-2-shard-astronauts-config"));
+            PrimaryFound found = PrimaryFound.fromSerializable(expectMsgClass(duration("5 seconds"),
+                    PrimaryFound.SERIALIZABLE_CLASS));
+            String path = found.getPrimaryPath();
+            assertTrue("Found path contains " + path, path.contains("member-2-shard-astronauts-config"));
         }};
     }
 
     @Test
     public void testOnReceiveMemberDown() throws Exception {
 
-        new JavaTestKit(system) {{
-            final Props props = ShardManager
-                .props("config", new MockClusterWrapper(),
-                    new MockConfiguration(), new DatastoreContext());
+        new JavaTestKit(getSystem()) {{
+            final ActorRef shardManager = getSystem().actorOf(newShardMgrProps());
 
-            final ActorRef subject = getSystem().actorOf(props);
+            MockClusterWrapper.sendMemberUp(shardManager, "member-2", getRef().path().toString());
 
-            MockClusterWrapper.sendMemberUp(subject, "member-2", getRef().path().toString());
+            shardManager.tell(new FindPrimary("astronauts").toSerializable(), getRef());
 
-            subject.tell(new FindPrimary("astronauts").toSerializable(), getRef());
+            expectMsgClass(duration("5 seconds"), PrimaryFound.SERIALIZABLE_CLASS);
 
-            expectMsgClass(duration("3 seconds"), PrimaryFound.SERIALIZABLE_CLASS);
+            MockClusterWrapper.sendMemberRemoved(shardManager, "member-2", getRef().path().toString());
 
-            MockClusterWrapper.sendMemberRemoved(subject, "member-2", getRef().path().toString());
+            shardManager.tell(new FindPrimary("astronauts").toSerializable(), getRef());
 
-            subject.tell(new FindPrimary("astronauts").toSerializable(), getRef());
-
-            expectMsgClass(duration("1 seconds"), PrimaryNotFound.SERIALIZABLE_CLASS);
+            expectMsgClass(duration("5 seconds"), PrimaryNotFound.SERIALIZABLE_CLASS);
         }};
     }
 
     @Test
-    public void testOnRecoveryJournalIsEmptied(){
-        MyJournal.addToJournal(1L, new ShardManager.SchemaContextModules(
-            ImmutableSet.of("foo")));
-
-        assertEquals(1, MyJournal.get().size());
-
-        new JavaTestKit(system) {{
-            final Props props = ShardManager
-                .props("config", new MockClusterWrapper(),
-                    new MockConfiguration(), new DatastoreContext());
-
-            final ActorRef subject = getSystem().actorOf(props);
-
-            // Send message to check that ShardManager is ready
-            subject.tell(new FindPrimary("unknown").toSerializable(), getRef());
-
-            expectMsgClass(duration("3 seconds"), PrimaryNotFound.SERIALIZABLE_CLASS);
-
-            assertEquals(0, MyJournal.get().size());
+    public void testOnRecoveryJournalIsCleaned() {
+        InMemoryJournal.addEntry(shardMgrID, 1L, new ShardManager.SchemaContextModules(
+                ImmutableSet.of("foo")));
+        InMemoryJournal.addEntry(shardMgrID, 2L, new ShardManager.SchemaContextModules(
+                ImmutableSet.of("bar")));
+        InMemoryJournal.addDeleteMessagesCompleteLatch(shardMgrID);
+
+        new JavaTestKit(getSystem()) {{
+            TestActorRef<TestShardManager> shardManager = TestActorRef.create(getSystem(),
+                    Props.create(new TestShardManagerCreator(shardMrgIDSuffix)));
+
+            shardManager.underlyingActor().waitForRecoveryComplete();
+            InMemoryJournal.waitForDeleteMessagesComplete(shardMgrID);
+
+            // Journal entries up to the last one should've been deleted
+            Map<Long, Object> journal = InMemoryJournal.get(shardMgrID);
+            synchronized (journal) {
+                assertEquals("Journal size", 1, journal.size());
+                assertEquals("Journal entry seq #", Long.valueOf(2), journal.keySet().iterator().next());
+            }
         }};
     }
 
     @Test
     public void testOnRecoveryPreviouslyKnownModulesAreDiscovered() throws Exception {
-        new JavaTestKit(system) {{
-            final Props props = ShardManager
-                .props("config", new MockClusterWrapper(),
-                    new MockConfiguration(), new DatastoreContext());
-            final TestActorRef<ShardManager> subject =
-                TestActorRef.create(system, props);
+        final ImmutableSet<String> persistedModules = ImmutableSet.of("foo", "bar");
+        InMemoryJournal.addEntry(shardMgrID, 1L, new ShardManager.SchemaContextModules(
+                persistedModules));
+        new JavaTestKit(getSystem()) {{
+            TestActorRef<TestShardManager> shardManager = TestActorRef.create(getSystem(),
+                    Props.create(new TestShardManagerCreator(shardMrgIDSuffix)));
 
-            subject.underlyingActor().onReceiveRecover(new ShardManager.SchemaContextModules(ImmutableSet.of("foo")));
+            shardManager.underlyingActor().waitForRecoveryComplete();
 
-            Collection<String> knownModules = subject.underlyingActor().getKnownModules();
+            Collection<String> knownModules = shardManager.underlyingActor().getKnownModules();
 
-            assertTrue(knownModules.contains("foo"));
+            assertEquals("getKnownModules", persistedModules, Sets.newHashSet(knownModules));
         }};
     }
 
     @Test
     public void testOnUpdateSchemaContextUpdateKnownModulesIfTheyContainASuperSetOfTheKnownModules()
-        throws Exception {
-        new JavaTestKit(system) {{
-            final Props props = ShardManager
-                .props("config", new MockClusterWrapper(),
-                    new MockConfiguration(), new DatastoreContext());
-            final TestActorRef<ShardManager> subject =
-                TestActorRef.create(system, props);
-
-            Collection<String> knownModules = subject.underlyingActor().getKnownModules();
+            throws Exception {
+        new JavaTestKit(getSystem()) {{
+            final TestActorRef<ShardManager> shardManager =
+                    TestActorRef.create(getSystem(), newShardMgrProps());
 
-            assertEquals(0, knownModules.size());
-
-            SchemaContext schemaContext = mock(SchemaContext.class);
-            Set<ModuleIdentifier> moduleIdentifierSet = new HashSet<>();
+            assertEquals("getKnownModules size", 0, shardManager.underlyingActor().getKnownModules().size());
 
             ModuleIdentifier foo = mock(ModuleIdentifier.class);
             when(foo.getNamespace()).thenReturn(new URI("foo"));
 
+            Set<ModuleIdentifier> moduleIdentifierSet = new HashSet<>();
             moduleIdentifierSet.add(foo);
 
+            SchemaContext schemaContext = mock(SchemaContext.class);
             when(schemaContext.getAllModuleIdentifiers()).thenReturn(moduleIdentifierSet);
 
-            subject.underlyingActor().onReceiveCommand(new UpdateSchemaContext(schemaContext));
-
-            assertTrue(knownModules.contains("foo"));
+            shardManager.underlyingActor().onReceiveCommand(new UpdateSchemaContext(schemaContext));
 
-            assertEquals(1, knownModules.size());
+            assertEquals("getKnownModules", Sets.newHashSet("foo"),
+                    Sets.newHashSet(shardManager.underlyingActor().getKnownModules()));
 
             ModuleIdentifier bar = mock(ModuleIdentifier.class);
             when(bar.getNamespace()).thenReturn(new URI("bar"));
 
             moduleIdentifierSet.add(bar);
 
-            subject.underlyingActor().onReceiveCommand(new UpdateSchemaContext(schemaContext));
-
-            assertTrue(knownModules.contains("bar"));
-
-            assertEquals(2, knownModules.size());
+            shardManager.underlyingActor().onReceiveCommand(new UpdateSchemaContext(schemaContext));
 
+            assertEquals("getKnownModules", Sets.newHashSet("foo", "bar"),
+                    Sets.newHashSet(shardManager.underlyingActor().getKnownModules()));
         }};
-
     }
 
-
     @Test
     public void testOnUpdateSchemaContextDoNotUpdateKnownModulesIfTheyDoNotContainASuperSetOfKnownModules()
-        throws Exception {
-        new JavaTestKit(system) {{
-            final Props props = ShardManager
-                .props("config", new MockClusterWrapper(),
-                    new MockConfiguration(), new DatastoreContext());
-            final TestActorRef<ShardManager> subject =
-                TestActorRef.create(system, props);
-
-            Collection<String> knownModules = subject.underlyingActor().getKnownModules();
-
-            assertEquals(0, knownModules.size());
+            throws Exception {
+        new JavaTestKit(getSystem()) {{
+            final TestActorRef<ShardManager> shardManager =
+                    TestActorRef.create(getSystem(), newShardMgrProps());
 
             SchemaContext schemaContext = mock(SchemaContext.class);
             Set<ModuleIdentifier> moduleIdentifierSet = new HashSet<>();
@@ -340,103 +285,65 @@ public class ShardManagerTest {
 
             when(schemaContext.getAllModuleIdentifiers()).thenReturn(moduleIdentifierSet);
 
-            subject.underlyingActor().onReceiveCommand(new UpdateSchemaContext(schemaContext));
-
-            assertTrue(knownModules.contains("foo"));
+            shardManager.underlyingActor().onReceiveCommand(new UpdateSchemaContext(schemaContext));
 
-            assertEquals(1, knownModules.size());
+            assertEquals("getKnownModules", Sets.newHashSet("foo"),
+                    Sets.newHashSet(shardManager.underlyingActor().getKnownModules()));
 
             //Create a completely different SchemaContext with only the bar module in it
-            schemaContext = mock(SchemaContext.class);
-            moduleIdentifierSet = new HashSet<>();
+            //schemaContext = mock(SchemaContext.class);
+            moduleIdentifierSet.clear();
             ModuleIdentifier bar = mock(ModuleIdentifier.class);
             when(bar.getNamespace()).thenReturn(new URI("bar"));
 
             moduleIdentifierSet.add(bar);
 
-            subject.underlyingActor().onReceiveCommand(new UpdateSchemaContext(schemaContext));
+            shardManager.underlyingActor().onReceiveCommand(new UpdateSchemaContext(schemaContext));
 
-            assertFalse(knownModules.contains("bar"));
-
-            assertEquals(1, knownModules.size());
+            assertEquals("getKnownModules", Sets.newHashSet("foo"),
+                    Sets.newHashSet(shardManager.underlyingActor().getKnownModules()));
 
         }};
-
-    }
-
-
-    private void sleep(long period){
-        Uninterruptibles.sleepUninterruptibly(period, TimeUnit.MILLISECONDS);
     }
 
-    public static class MyJournal extends AsyncWriteJournal {
-
-        private static Map<Long, Object> journal = Maps.newTreeMap();
 
-        public static void addToJournal(Long sequenceNr, Object value){
-            journal.put(sequenceNr, value);
-        }
+    private static class TestShardManager extends ShardManager {
+        private final CountDownLatch recoveryComplete = new CountDownLatch(1);
 
-        public static Map<Long, Object> get(){
-            return journal;
+        TestShardManager(String shardMrgIDSuffix) {
+            super(shardMrgIDSuffix, new MockClusterWrapper(), new MockConfiguration(),
+                    DatastoreContext.newBuilder().build());
         }
 
-        public static void clear(){
-            journal.clear();
-        }
-
-        @Override public Future<Void> doAsyncReplayMessages(final String persistenceId, long fromSequenceNr, long toSequenceNr, long max,
-            final Procedure<PersistentRepr> replayCallback) {
-            if(journal.size() == 0){
-                return Futures.successful(null);
-            }
-            return Futures.future(new Callable<Void>() {
-                @Override
-                public Void call() throws Exception {
-                    for (Map.Entry<Long, Object> entry : journal.entrySet()) {
-                        PersistentRepr persistentMessage =
-                            new PersistentImpl(entry.getValue(), entry.getKey(), persistenceId,
-                                false, null, null);
-                        replayCallback.apply(persistentMessage);
-                    }
-                    return null;
+        @Override
+        public void handleRecover(Object message) throws Exception {
+            try {
+                super.handleRecover(message);
+            } finally {
+                if(message instanceof RecoveryCompleted) {
+                    recoveryComplete.countDown();
                 }
-            }, context().dispatcher());
+            }
         }
 
-        @Override public Future<Long> doAsyncReadHighestSequenceNr(String s, long l) {
-            return Futures.successful(-1L);
+        void waitForRecoveryComplete() {
+            assertEquals("Recovery complete", true,
+                    Uninterruptibles.awaitUninterruptibly(recoveryComplete, 5, TimeUnit.SECONDS));
         }
+    }
 
-        @Override public Future<Void> doAsyncWriteMessages(
-            final Iterable<PersistentRepr> persistentReprs) {
-            return Futures.future(new Callable<Void>() {
-                @Override
-                public Void call() throws Exception {
-                    for (PersistentRepr repr : persistentReprs){
-                        if(repr.payload() instanceof ShardManager.SchemaContextModules) {
-                            journal.put(repr.sequenceNr(), repr.payload());
-                        }
-                    }
-                    return null;
-                }
-            }, context().dispatcher());
-        }
+    @SuppressWarnings("serial")
+    static class TestShardManagerCreator implements Creator<TestShardManager> {
+        String shardMrgIDSuffix;
 
-        @Override public Future<Void> doAsyncWriteConfirmations(
-            Iterable<PersistentConfirmation> persistentConfirmations) {
-            return Futures.successful(null);
+        TestShardManagerCreator(String shardMrgIDSuffix) {
+            this.shardMrgIDSuffix = shardMrgIDSuffix;
         }
 
-        @Override public Future<Void> doAsyncDeleteMessages(Iterable<PersistentId> persistentIds,
-            boolean b) {
-            clear();
-            return Futures.successful(null);
+        @Override
+        public TestShardManager create() throws Exception {
+            return new TestShardManager(shardMrgIDSuffix);
         }
 
-        @Override public Future<Void> doAsyncDeleteMessagesTo(String s, long l, boolean b) {
-            clear();
-            return Futures.successful(null);
-        }
     }
 }
index 2051c9debe88c69c071663df511fbff130f325ed..f183bb319ee04df852134264ec66a475a53c13ff 100644 (file)
@@ -1,27 +1,38 @@
 package org.opendaylight.controller.cluster.datastore;
 
 import akka.actor.ActorRef;
-import akka.actor.ActorSystem;
 import akka.actor.Props;
-import akka.event.Logging;
+import akka.dispatch.Dispatchers;
+import akka.dispatch.OnComplete;
 import akka.japi.Creator;
+import akka.pattern.Patterns;
 import akka.testkit.JavaTestKit;
 import akka.testkit.TestActorRef;
+import akka.util.Timeout;
+import com.google.common.base.Function;
 import com.google.common.base.Optional;
 import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.MoreExecutors;
 import org.junit.After;
-import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.InOrder;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
 import org.opendaylight.controller.cluster.datastore.identifiers.ShardIdentifier;
+import org.opendaylight.controller.cluster.datastore.messages.AbortTransaction;
+import org.opendaylight.controller.cluster.datastore.messages.AbortTransactionReply;
+import org.opendaylight.controller.cluster.datastore.messages.CanCommitTransaction;
+import org.opendaylight.controller.cluster.datastore.messages.CanCommitTransactionReply;
+import org.opendaylight.controller.cluster.datastore.messages.CommitTransaction;
 import org.opendaylight.controller.cluster.datastore.messages.CommitTransactionReply;
 import org.opendaylight.controller.cluster.datastore.messages.CreateTransaction;
 import org.opendaylight.controller.cluster.datastore.messages.EnableNotification;
-import org.opendaylight.controller.cluster.datastore.messages.ForwardedCommitTransaction;
+import org.opendaylight.controller.cluster.datastore.messages.ForwardedReadyTransaction;
 import org.opendaylight.controller.cluster.datastore.messages.PeerAddressResolved;
+import org.opendaylight.controller.cluster.datastore.messages.ReadyTransactionReply;
 import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListener;
 import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListenerReply;
 import org.opendaylight.controller.cluster.datastore.messages.UpdateSchemaContext;
@@ -61,7 +72,9 @@ import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import scala.concurrent.duration.Duration;
+import scala.concurrent.Await;
+import scala.concurrent.Future;
+import scala.concurrent.duration.FiniteDuration;
 import java.io.IOException;
 import java.util.Collections;
 import java.util.HashSet;
@@ -69,24 +82,33 @@ import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.inOrder;
 
 public class ShardTest extends AbstractActorTest {
 
-    private static final DatastoreContext DATA_STORE_CONTEXT =
-            new DatastoreContext("", null, Duration.create(10, TimeUnit.MINUTES), 5, 3, 5000, 500);
-
     private static final SchemaContext SCHEMA_CONTEXT = TestModel.createTestContext();
 
     private static final ShardIdentifier IDENTIFIER = ShardIdentifier.builder().memberName("member-1")
             .shardName("inventory").type("config").build();
 
+    private static final AtomicInteger NEXT_SHARD_NUM = new AtomicInteger();
+
+    private static String shardName() {
+        return "shard" + NEXT_SHARD_NUM.getAndIncrement();
+    }
+
+    private DatastoreContext dataStoreContext = DatastoreContext.newBuilder().
+            shardJournalRecoveryLogBatchSize(3).shardSnapshotBatchCount(5000).build();
+
     @Before
     public void setUp() {
         System.setProperty("shard.persistent", "false");
@@ -103,7 +125,7 @@ public class ShardTest extends AbstractActorTest {
 
     private Props newShardProps() {
         return Shard.props(IDENTIFIER, Collections.<ShardIdentifier,String>emptyMap(),
-                DATA_STORE_CONTEXT, SCHEMA_CONTEXT);
+                dataStoreContext, SCHEMA_CONTEXT);
     }
 
     @Test
@@ -178,7 +200,7 @@ public class ShardTest extends AbstractActorTest {
 
             Props props = Shard.props(identifier,
                     Collections.<ShardIdentifier, String>singletonMap(identifier, null),
-                    DATA_STORE_CONTEXT, SCHEMA_CONTEXT);
+                    dataStoreContext, SCHEMA_CONTEXT);
             final ActorRef subject = getSystem().actorOf(props, "testPeerAddressResolved");
 
             new Within(duration("3 seconds")) {
@@ -202,11 +224,10 @@ public class ShardTest extends AbstractActorTest {
         NormalizedNodeToNodeCodec codec =
             new NormalizedNodeToNodeCodec(SCHEMA_CONTEXT);
 
-        ref.underlyingActor().writeToStore(TestModel.TEST_PATH, ImmutableNodes.containerNode(
-                TestModel.TEST_QNAME));
+        writeToStore(ref, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
 
         YangInstanceIdentifier root = YangInstanceIdentifier.builder().build();
-        NormalizedNode<?,?> expected = ref.underlyingActor().readStore(root);
+        NormalizedNode<?,?> expected = readStore(ref, root);
 
         NormalizedNodeMessages.Container encode = codec.encode(expected);
 
@@ -216,7 +237,7 @@ public class ShardTest extends AbstractActorTest {
 
         ref.underlyingActor().onReceiveCommand(applySnapshot);
 
-        NormalizedNode<?,?> actual = ref.underlyingActor().readStore(root);
+        NormalizedNode<?,?> actual = readStore(ref, root);
 
         assertEquals(expected, actual);
     }
@@ -236,7 +257,7 @@ public class ShardTest extends AbstractActorTest {
 
         shard.underlyingActor().onReceiveCommand(applyState);
 
-        NormalizedNode<?,?> actual = shard.underlyingActor().readStore(TestModel.TEST_PATH);
+        NormalizedNode<?,?> actual = readStore(shard, TestModel.TEST_PATH);
         assertEquals("Applied state", node, actual);
     }
 
@@ -295,7 +316,7 @@ public class ShardTest extends AbstractActorTest {
             @Override
             public Shard create() throws Exception {
                 return new Shard(IDENTIFIER, Collections.<ShardIdentifier,String>emptyMap(),
-                        DATA_STORE_CONTEXT, SCHEMA_CONTEXT) {
+                        dataStoreContext, SCHEMA_CONTEXT) {
                     @Override
                     protected void onRecoveryComplete() {
                         try {
@@ -315,7 +336,7 @@ public class ShardTest extends AbstractActorTest {
 
         // Verify data in the data store.
 
-        NormalizedNode<?, ?> outerList = shard.underlyingActor().readStore(TestModel.OUTER_LIST_PATH);
+        NormalizedNode<?, ?> outerList = readStore(shard, TestModel.OUTER_LIST_PATH);
         assertNotNull(TestModel.OUTER_LIST_QNAME.getLocalName() + " not found", outerList);
         assertTrue(TestModel.OUTER_LIST_QNAME.getLocalName() + " value is not Iterable",
                 outerList.getValue() instanceof Iterable);
@@ -353,49 +374,682 @@ public class ShardTest extends AbstractActorTest {
         return new CompositeModificationPayload(compMod.toSerializable());
     }
 
-    @SuppressWarnings("unchecked")
+    private DOMStoreThreePhaseCommitCohort setupMockWriteTransaction(String cohortName,
+            InMemoryDOMDataStore dataStore, YangInstanceIdentifier path, NormalizedNode data,
+            MutableCompositeModification modification) {
+        return setupMockWriteTransaction(cohortName, dataStore, path, data, modification, null);
+    }
+
+    private DOMStoreThreePhaseCommitCohort setupMockWriteTransaction(String cohortName,
+            InMemoryDOMDataStore dataStore, YangInstanceIdentifier path, NormalizedNode data,
+            MutableCompositeModification modification,
+            final Function<DOMStoreThreePhaseCommitCohort,ListenableFuture<Void>> preCommit) {
+
+        DOMStoreWriteTransaction tx = dataStore.newWriteOnlyTransaction();
+        tx.write(path, data);
+        final DOMStoreThreePhaseCommitCohort realCohort = tx.ready();
+        DOMStoreThreePhaseCommitCohort cohort = mock(DOMStoreThreePhaseCommitCohort.class, cohortName);
+
+        doAnswer(new Answer<ListenableFuture<Boolean>>() {
+            @Override
+            public ListenableFuture<Boolean> answer(InvocationOnMock invocation) {
+                return realCohort.canCommit();
+            }
+        }).when(cohort).canCommit();
+
+        doAnswer(new Answer<ListenableFuture<Void>>() {
+            @Override
+            public ListenableFuture<Void> answer(InvocationOnMock invocation) throws Throwable {
+                if(preCommit != null) {
+                    return preCommit.apply(realCohort);
+                } else {
+                    return realCohort.preCommit();
+                }
+            }
+        }).when(cohort).preCommit();
+
+        doAnswer(new Answer<ListenableFuture<Void>>() {
+            @Override
+            public ListenableFuture<Void> answer(InvocationOnMock invocation) throws Throwable {
+                return realCohort.commit();
+            }
+        }).when(cohort).commit();
+
+        doAnswer(new Answer<ListenableFuture<Void>>() {
+            @Override
+            public ListenableFuture<Void> answer(InvocationOnMock invocation) throws Throwable {
+                return realCohort.abort();
+            }
+        }).when(cohort).abort();
+
+        modification.addModification(new WriteModification(path, data, SCHEMA_CONTEXT));
+
+        return cohort;
+    }
+
+    @SuppressWarnings({ "unchecked" })
     @Test
-    public void testForwardedCommitTransactionWithPersistence() throws IOException {
+    public void testConcurrentThreePhaseCommits() throws Throwable {
         System.setProperty("shard.persistent", "true");
+        new ShardTestKit(getSystem()) {{
+            final TestActorRef<Shard> shard = TestActorRef.create(getSystem(),
+                    newShardProps().withDispatcher(Dispatchers.DefaultDispatcherId()), shardName());
+
+            waitUntilLeader(shard);
+
+            // Setup 3 simulated transactions with mock cohorts backed by real cohorts.
+
+            InMemoryDOMDataStore dataStore = shard.underlyingActor().getDataStore();
+
+            String transactionID1 = "tx1";
+            MutableCompositeModification modification1 = new MutableCompositeModification();
+            DOMStoreThreePhaseCommitCohort cohort1 = setupMockWriteTransaction("cohort1", dataStore,
+                    TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME), modification1);
+
+            String transactionID2 = "tx2";
+            MutableCompositeModification modification2 = new MutableCompositeModification();
+            DOMStoreThreePhaseCommitCohort cohort2 = setupMockWriteTransaction("cohort2", dataStore,
+                    TestModel.OUTER_LIST_PATH,
+                    ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME).build(),
+                    modification2);
+
+            String transactionID3 = "tx3";
+            MutableCompositeModification modification3 = new MutableCompositeModification();
+            DOMStoreThreePhaseCommitCohort cohort3 = setupMockWriteTransaction("cohort3", dataStore,
+                    YangInstanceIdentifier.builder(TestModel.OUTER_LIST_PATH)
+                        .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1).build(),
+                    ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1),
+                    modification3);
+
+            long timeoutSec = 5;
+            final FiniteDuration duration = FiniteDuration.create(timeoutSec, TimeUnit.SECONDS);
+            final Timeout timeout = new Timeout(duration);
+
+            // Simulate the ForwardedReadyTransaction message for the first Tx that would be sent
+            // by the ShardTransaction.
+
+            shard.tell(new ForwardedReadyTransaction(transactionID1, cohort1, modification1, true), getRef());
+            ReadyTransactionReply readyReply = ReadyTransactionReply.fromSerializable(
+                    expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS));
+            assertEquals("Cohort path", shard.path().toString(), readyReply.getCohortPath());
+
+            // Send the CanCommitTransaction message for the first Tx.
+
+            shard.tell(new CanCommitTransaction(transactionID1).toSerializable(), getRef());
+            CanCommitTransactionReply canCommitReply = CanCommitTransactionReply.fromSerializable(
+                    expectMsgClass(duration, CanCommitTransactionReply.SERIALIZABLE_CLASS));
+            assertEquals("Can commit", true, canCommitReply.getCanCommit());
+
+            // Send the ForwardedReadyTransaction for the next 2 Tx's.
+
+            shard.tell(new ForwardedReadyTransaction(transactionID2, cohort2, modification2, true), getRef());
+            expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS);
+
+            shard.tell(new ForwardedReadyTransaction(transactionID3, cohort3, modification3, true), getRef());
+            expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS);
+
+            // Send the CanCommitTransaction message for the next 2 Tx's. These should get queued and
+            // processed after the first Tx completes.
+
+            Future<Object> canCommitFuture1 = Patterns.ask(shard,
+                    new CanCommitTransaction(transactionID2).toSerializable(), timeout);
+
+            Future<Object> canCommitFuture2 = Patterns.ask(shard,
+                    new CanCommitTransaction(transactionID3).toSerializable(), timeout);
+
+            // Send the CommitTransaction message for the first Tx. After it completes, it should
+            // trigger the 2nd Tx to proceed which should in turn then trigger the 3rd.
+
+            shard.tell(new CommitTransaction(transactionID1).toSerializable(), getRef());
+            expectMsgClass(duration, CommitTransactionReply.SERIALIZABLE_CLASS);
+
+            // Wait for the next 2 Tx's to complete.
+
+            final AtomicReference<Throwable> caughtEx = new AtomicReference<>();
+            final CountDownLatch commitLatch = new CountDownLatch(2);
+
+            class OnFutureComplete extends OnComplete<Object> {
+                private final Class<?> expRespType;
+
+                OnFutureComplete(Class<?> expRespType) {
+                    this.expRespType = expRespType;
+                }
+
+                @Override
+                public void onComplete(Throwable error, Object resp) {
+                    if(error != null) {
+                        System.out.println(new java.util.Date()+": "+getClass().getSimpleName() + " failure: "+error);
+                        caughtEx.set(new AssertionError(getClass().getSimpleName() + " failure", error));
+                    } else {
+                        try {
+                            assertEquals("Commit response type", expRespType, resp.getClass());
+                            onSuccess(resp);
+                        } catch (Exception e) {
+                            caughtEx.set(e);
+                        }
+                    }
+                }
+
+                void onSuccess(Object resp) throws Exception {
+                }
+            }
+
+            class OnCommitFutureComplete extends OnFutureComplete {
+                OnCommitFutureComplete() {
+                    super(CommitTransactionReply.SERIALIZABLE_CLASS);
+                }
+
+                @Override
+                public void onComplete(Throwable error, Object resp) {
+                    super.onComplete(error, resp);
+                    commitLatch.countDown();
+                }
+            }
+
+            class OnCanCommitFutureComplete extends OnFutureComplete {
+                private final String transactionID;
 
+                OnCanCommitFutureComplete(String transactionID) {
+                    super(CanCommitTransactionReply.SERIALIZABLE_CLASS);
+                    this.transactionID = transactionID;
+                }
+
+                @Override
+                void onSuccess(Object resp) throws Exception {
+                    CanCommitTransactionReply canCommitReply =
+                            CanCommitTransactionReply.fromSerializable(resp);
+                    assertEquals("Can commit", true, canCommitReply.getCanCommit());
+
+                    Future<Object> commitFuture = Patterns.ask(shard,
+                            new CommitTransaction(transactionID).toSerializable(), timeout);
+                    commitFuture.onComplete(new OnCommitFutureComplete(), getSystem().dispatcher());
+                }
+            }
+
+            canCommitFuture1.onComplete(new OnCanCommitFutureComplete(transactionID2),
+                    getSystem().dispatcher());
+
+            canCommitFuture2.onComplete(new OnCanCommitFutureComplete(transactionID3),
+                    getSystem().dispatcher());
+
+            boolean done = commitLatch.await(timeoutSec, TimeUnit.SECONDS);
+
+            if(caughtEx.get() != null) {
+                throw caughtEx.get();
+            }
+
+            assertEquals("Commits complete", true, done);
+
+            InOrder inOrder = inOrder(cohort1, cohort2, cohort3);
+            inOrder.verify(cohort1).canCommit();
+            inOrder.verify(cohort1).preCommit();
+            inOrder.verify(cohort1).commit();
+            inOrder.verify(cohort2).canCommit();
+            inOrder.verify(cohort2).preCommit();
+            inOrder.verify(cohort2).commit();
+            inOrder.verify(cohort3).canCommit();
+            inOrder.verify(cohort3).preCommit();
+            inOrder.verify(cohort3).commit();
+
+            // Verify data in the data store.
+
+            NormalizedNode<?, ?> outerList = readStore(shard, TestModel.OUTER_LIST_PATH);
+            assertNotNull(TestModel.OUTER_LIST_QNAME.getLocalName() + " not found", outerList);
+            assertTrue(TestModel.OUTER_LIST_QNAME.getLocalName() + " value is not Iterable",
+                    outerList.getValue() instanceof Iterable);
+            Object entry = ((Iterable<Object>)outerList.getValue()).iterator().next();
+            assertTrue(TestModel.OUTER_LIST_QNAME.getLocalName() + " entry is not MapEntryNode",
+                       entry instanceof MapEntryNode);
+            MapEntryNode mapEntry = (MapEntryNode)entry;
+            Optional<DataContainerChild<? extends PathArgument, ?>> idLeaf =
+                    mapEntry.getChild(new YangInstanceIdentifier.NodeIdentifier(TestModel.ID_QNAME));
+            assertTrue("Missing leaf " + TestModel.ID_QNAME.getLocalName(), idLeaf.isPresent());
+            assertEquals(TestModel.ID_QNAME.getLocalName() + " value", 1, idLeaf.get().getValue());
+
+            assertEquals("Last log index", 2, shard.underlyingActor().getShardMBean().getLastLogIndex());
+        }};
+    }
+
+    @Test
+    public void testCommitPhaseFailure() throws Throwable {
         new ShardTestKit(getSystem()) {{
-            TestActorRef<Shard> shard = TestActorRef.create(getSystem(), newShardProps());
+            final TestActorRef<Shard> shard = TestActorRef.create(getSystem(),
+                    newShardProps().withDispatcher(Dispatchers.DefaultDispatcherId()), shardName());
 
             waitUntilLeader(shard);
 
-            NormalizedNode<?, ?> node = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
+            // Setup 2 simulated transactions with mock cohorts. The first one fails in the
+            // commit phase.
+
+            String transactionID1 = "tx1";
+            MutableCompositeModification modification1 = new MutableCompositeModification();
+            DOMStoreThreePhaseCommitCohort cohort1 = mock(DOMStoreThreePhaseCommitCohort.class, "cohort1");
+            doReturn(Futures.immediateFuture(Boolean.TRUE)).when(cohort1).canCommit();
+            doReturn(Futures.immediateFuture(null)).when(cohort1).preCommit();
+            doReturn(Futures.immediateFailedFuture(new IllegalStateException("mock"))).when(cohort1).commit();
+
+            String transactionID2 = "tx2";
+            MutableCompositeModification modification2 = new MutableCompositeModification();
+            DOMStoreThreePhaseCommitCohort cohort2 = mock(DOMStoreThreePhaseCommitCohort.class, "cohort2");
+            doReturn(Futures.immediateFuture(Boolean.TRUE)).when(cohort2).canCommit();
+
+            FiniteDuration duration = duration("5 seconds");
+            final Timeout timeout = new Timeout(duration);
+
+            // Simulate the ForwardedReadyTransaction messages that would be sent
+            // by the ShardTransaction.
+
+            shard.tell(new ForwardedReadyTransaction(transactionID1, cohort1, modification1, true), getRef());
+            expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS);
 
-            DOMStoreThreePhaseCommitCohort cohort = mock(DOMStoreThreePhaseCommitCohort.class);
-            doReturn(Futures.immediateFuture(null)).when(cohort).commit();
+            shard.tell(new ForwardedReadyTransaction(transactionID2, cohort2, modification2, true), getRef());
+            expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS);
 
+            // Send the CanCommitTransaction message for the first Tx.
+
+            shard.tell(new CanCommitTransaction(transactionID1).toSerializable(), getRef());
+            CanCommitTransactionReply canCommitReply = CanCommitTransactionReply.fromSerializable(
+                    expectMsgClass(duration, CanCommitTransactionReply.SERIALIZABLE_CLASS));
+            assertEquals("Can commit", true, canCommitReply.getCanCommit());
+
+            // Send the CanCommitTransaction message for the 2nd Tx. This should get queued and
+            // processed after the first Tx completes.
+
+            Future<Object> canCommitFuture = Patterns.ask(shard,
+                    new CanCommitTransaction(transactionID2).toSerializable(), timeout);
+
+            // Send the CommitTransaction message for the first Tx. This should send back an error
+            // and trigger the 2nd Tx to proceed.
+
+            shard.tell(new CommitTransaction(transactionID1).toSerializable(), getRef());
+            expectMsgClass(duration, akka.actor.Status.Failure.class);
+
+            // Wait for the 2nd Tx to complete the canCommit phase.
+
+            final CountDownLatch latch = new CountDownLatch(1);
+            canCommitFuture.onComplete(new OnComplete<Object>() {
+                @Override
+                public void onComplete(Throwable t, Object resp) {
+                    latch.countDown();
+                }
+            }, getSystem().dispatcher());
+
+            assertEquals("2nd CanCommit complete", true, latch.await(5, TimeUnit.SECONDS));
+
+            InOrder inOrder = inOrder(cohort1, cohort2);
+            inOrder.verify(cohort1).canCommit();
+            inOrder.verify(cohort1).preCommit();
+            inOrder.verify(cohort1).commit();
+            inOrder.verify(cohort2).canCommit();
+        }};
+    }
+
+    @Test
+    public void testPreCommitPhaseFailure() throws Throwable {
+        new ShardTestKit(getSystem()) {{
+            final TestActorRef<Shard> shard = TestActorRef.create(getSystem(),
+                    newShardProps().withDispatcher(Dispatchers.DefaultDispatcherId()), shardName());
+
+            waitUntilLeader(shard);
+
+            String transactionID = "tx1";
             MutableCompositeModification modification = new MutableCompositeModification();
-            modification.addModification(new WriteModification(TestModel.TEST_PATH, node,
-                    SCHEMA_CONTEXT));
+            DOMStoreThreePhaseCommitCohort cohort = mock(DOMStoreThreePhaseCommitCohort.class, "cohort1");
+            doReturn(Futures.immediateFuture(Boolean.TRUE)).when(cohort).canCommit();
+            doReturn(Futures.immediateFailedFuture(new IllegalStateException("mock"))).when(cohort).preCommit();
+
+            FiniteDuration duration = duration("5 seconds");
+
+            // Simulate the ForwardedReadyTransaction messages that would be sent
+            // by the ShardTransaction.
 
-            shard.tell(new ForwardedCommitTransaction(cohort, modification), getRef());
+            shard.tell(new ForwardedReadyTransaction(transactionID, cohort, modification, true), getRef());
+            expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS);
 
-            expectMsgClass(duration("5 seconds"), CommitTransactionReply.SERIALIZABLE_CLASS);
+            // Send the CanCommitTransaction message.
 
-            verify(cohort).commit();
+            shard.tell(new CanCommitTransaction(transactionID).toSerializable(), getRef());
+            CanCommitTransactionReply canCommitReply = CanCommitTransactionReply.fromSerializable(
+                    expectMsgClass(duration, CanCommitTransactionReply.SERIALIZABLE_CLASS));
+            assertEquals("Can commit", true, canCommitReply.getCanCommit());
 
-            assertEquals("Last log index", 0, shard.underlyingActor().getShardMBean().getLastLogIndex());
+            // Send the CommitTransaction message. This should send back an error
+            // for preCommit failure.
+
+            shard.tell(new CommitTransaction(transactionID).toSerializable(), getRef());
+            expectMsgClass(duration, akka.actor.Status.Failure.class);
+
+            InOrder inOrder = inOrder(cohort);
+            inOrder.verify(cohort).canCommit();
+            inOrder.verify(cohort).preCommit();
+        }};
+    }
+
+    @Test
+    public void testCanCommitPhaseFailure() throws Throwable {
+        new ShardTestKit(getSystem()) {{
+            final TestActorRef<Shard> shard = TestActorRef.create(getSystem(),
+                    newShardProps().withDispatcher(Dispatchers.DefaultDispatcherId()), shardName());
+
+            waitUntilLeader(shard);
+
+            final FiniteDuration duration = duration("5 seconds");
+
+            String transactionID = "tx1";
+            MutableCompositeModification modification = new MutableCompositeModification();
+            DOMStoreThreePhaseCommitCohort cohort = mock(DOMStoreThreePhaseCommitCohort.class, "cohort1");
+            doReturn(Futures.immediateFailedFuture(new IllegalStateException("mock"))).when(cohort).canCommit();
+
+            // Simulate the ForwardedReadyTransaction messages that would be sent
+            // by the ShardTransaction.
+
+            shard.tell(new ForwardedReadyTransaction(transactionID, cohort, modification, true), getRef());
+            expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS);
+
+            // Send the CanCommitTransaction message.
+
+            shard.tell(new CanCommitTransaction(transactionID).toSerializable(), getRef());
+            expectMsgClass(duration, akka.actor.Status.Failure.class);
+        }};
+    }
+
+    @Test
+    public void testAbortBeforeFinishCommit() throws Throwable {
+        System.setProperty("shard.persistent", "true");
+        new ShardTestKit(getSystem()) {{
+            final TestActorRef<Shard> shard = TestActorRef.create(getSystem(),
+                    newShardProps().withDispatcher(Dispatchers.DefaultDispatcherId()), shardName());
+
+            waitUntilLeader(shard);
+
+            final FiniteDuration duration = duration("5 seconds");
+            final Timeout timeout = new Timeout(duration);
+
+            InMemoryDOMDataStore dataStore = shard.underlyingActor().getDataStore();
+
+            final String transactionID = "tx1";
+            final CountDownLatch abortComplete = new CountDownLatch(1);
+            Function<DOMStoreThreePhaseCommitCohort,ListenableFuture<Void>> preCommit =
+                          new Function<DOMStoreThreePhaseCommitCohort,ListenableFuture<Void>>() {
+                @Override
+                public ListenableFuture<Void> apply(final DOMStoreThreePhaseCommitCohort cohort) {
+                    ListenableFuture<Void> preCommitFuture = cohort.preCommit();
+
+                    Future<Object> abortFuture = Patterns.ask(shard,
+                            new AbortTransaction(transactionID).toSerializable(), timeout);
+                    abortFuture.onComplete(new OnComplete<Object>() {
+                        @Override
+                        public void onComplete(Throwable e, Object resp) {
+                            abortComplete.countDown();
+                        }
+                    }, getSystem().dispatcher());
+
+                    return preCommitFuture;
+                }
+            };
+
+            MutableCompositeModification modification = new MutableCompositeModification();
+            DOMStoreThreePhaseCommitCohort cohort = setupMockWriteTransaction("cohort1", dataStore,
+                    TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME),
+                    modification, preCommit);
+
+            shard.tell(new ForwardedReadyTransaction(transactionID, cohort, modification, true), getRef());
+            expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS);
+
+            shard.tell(new CanCommitTransaction(transactionID).toSerializable(), getRef());
+            CanCommitTransactionReply canCommitReply = CanCommitTransactionReply.fromSerializable(
+                    expectMsgClass(duration, CanCommitTransactionReply.SERIALIZABLE_CLASS));
+            assertEquals("Can commit", true, canCommitReply.getCanCommit());
+
+            Future<Object> commitFuture = Patterns.ask(shard,
+                    new CommitTransaction(transactionID).toSerializable(), timeout);
+
+            assertEquals("Abort complete", true, abortComplete.await(5, TimeUnit.SECONDS));
+
+            Await.result(commitFuture, duration);
+
+            NormalizedNode<?, ?> node = readStore(shard, TestModel.TEST_PATH);
+            assertNotNull(TestModel.TEST_QNAME.getLocalName() + " not found", node);
+        }};
+    }
+
+    @Test
+    public void testTransactionCommitTimeout() throws Throwable {
+        dataStoreContext = DatastoreContext.newBuilder().shardTransactionCommitTimeoutInSeconds(1).build();
+
+        new ShardTestKit(getSystem()) {{
+            final TestActorRef<Shard> shard = TestActorRef.create(getSystem(),
+                    newShardProps().withDispatcher(Dispatchers.DefaultDispatcherId()), shardName());
+
+            waitUntilLeader(shard);
+
+            final FiniteDuration duration = duration("5 seconds");
+
+            InMemoryDOMDataStore dataStore = shard.underlyingActor().getDataStore();
+
+            writeToStore(shard, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
+            writeToStore(shard, TestModel.OUTER_LIST_PATH,
+                    ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME).build());
+
+            // Create 1st Tx - will timeout
+
+            String transactionID1 = "tx1";
+            MutableCompositeModification modification1 = new MutableCompositeModification();
+            DOMStoreThreePhaseCommitCohort cohort1 = setupMockWriteTransaction("cohort1", dataStore,
+                    YangInstanceIdentifier.builder(TestModel.OUTER_LIST_PATH)
+                        .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1).build(),
+                    ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1),
+                    modification1);
+
+            // Create 2nd Tx
+
+            String transactionID2 = "tx3";
+            MutableCompositeModification modification2 = new MutableCompositeModification();
+            YangInstanceIdentifier listNodePath = YangInstanceIdentifier.builder(TestModel.OUTER_LIST_PATH)
+                .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 2).build();
+            DOMStoreThreePhaseCommitCohort cohort2 = setupMockWriteTransaction("cohort3", dataStore,
+                    listNodePath,
+                    ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 2),
+                    modification2);
+
+            // Ready the Tx's
+
+            shard.tell(new ForwardedReadyTransaction(transactionID1, cohort1, modification1, true), getRef());
+            expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS);
+
+            shard.tell(new ForwardedReadyTransaction(transactionID2, cohort2, modification2, true), getRef());
+            expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS);
+
+            // canCommit 1st Tx. We don't send the commit so it should timeout.
+
+            shard.tell(new CanCommitTransaction(transactionID1).toSerializable(), getRef());
+            expectMsgClass(duration, CanCommitTransactionReply.SERIALIZABLE_CLASS);
+
+            // canCommit the 2nd Tx - it should complete after the 1st Tx times out.
+
+            shard.tell(new CanCommitTransaction(transactionID2).toSerializable(), getRef());
+            expectMsgClass(duration, CanCommitTransactionReply.SERIALIZABLE_CLASS);
+
+            // Commit the 2nd Tx.
+
+            shard.tell(new CommitTransaction(transactionID2).toSerializable(), getRef());
+            expectMsgClass(duration, CommitTransactionReply.SERIALIZABLE_CLASS);
+
+            NormalizedNode<?, ?> node = readStore(shard, listNodePath);
+            assertNotNull(listNodePath + " not found", node);
+        }};
+    }
+
+    @Test
+    public void testTransactionCommitQueueCapacityExceeded() throws Throwable {
+        dataStoreContext = DatastoreContext.newBuilder().shardTransactionCommitQueueCapacity(1).build();
+
+        new ShardTestKit(getSystem()) {{
+            final TestActorRef<Shard> shard = TestActorRef.create(getSystem(),
+                    newShardProps().withDispatcher(Dispatchers.DefaultDispatcherId()), shardName());
+
+            waitUntilLeader(shard);
+
+            final FiniteDuration duration = duration("5 seconds");
+
+            InMemoryDOMDataStore dataStore = shard.underlyingActor().getDataStore();
+
+            String transactionID1 = "tx1";
+            MutableCompositeModification modification1 = new MutableCompositeModification();
+            DOMStoreThreePhaseCommitCohort cohort1 = setupMockWriteTransaction("cohort1", dataStore,
+                    TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME), modification1);
+
+            String transactionID2 = "tx2";
+            MutableCompositeModification modification2 = new MutableCompositeModification();
+            DOMStoreThreePhaseCommitCohort cohort2 = setupMockWriteTransaction("cohort2", dataStore,
+                    TestModel.OUTER_LIST_PATH,
+                    ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME).build(),
+                    modification2);
+
+            String transactionID3 = "tx3";
+            MutableCompositeModification modification3 = new MutableCompositeModification();
+            DOMStoreThreePhaseCommitCohort cohort3 = setupMockWriteTransaction("cohort3", dataStore,
+                    TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME), modification3);
+
+            // Ready the Tx's
+
+            shard.tell(new ForwardedReadyTransaction(transactionID1, cohort1, modification1, true), getRef());
+            expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS);
+
+            shard.tell(new ForwardedReadyTransaction(transactionID2, cohort2, modification2, true), getRef());
+            expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS);
+
+            shard.tell(new ForwardedReadyTransaction(transactionID3, cohort3, modification3, true), getRef());
+            expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS);
+
+            // canCommit 1st Tx.
+
+            shard.tell(new CanCommitTransaction(transactionID1).toSerializable(), getRef());
+            expectMsgClass(duration, CanCommitTransactionReply.SERIALIZABLE_CLASS);
+
+            // canCommit the 2nd Tx - it should get queued.
+
+            shard.tell(new CanCommitTransaction(transactionID2).toSerializable(), getRef());
+
+            // canCommit the 3rd Tx - should exceed queue capacity and fail.
+
+            shard.tell(new CanCommitTransaction(transactionID3).toSerializable(), getRef());
+            expectMsgClass(duration, akka.actor.Status.Failure.class);
+        }};
+    }
+
+    @Test
+    public void testCanCommitBeforeReadyFailure() throws Throwable {
+        new ShardTestKit(getSystem()) {{
+            final TestActorRef<Shard> shard = TestActorRef.create(getSystem(),
+                    newShardProps().withDispatcher(Dispatchers.DefaultDispatcherId()), shardName());
+
+            shard.tell(new CanCommitTransaction("tx").toSerializable(), getRef());
+            expectMsgClass(duration("5 seconds"), akka.actor.Status.Failure.class);
+        }};
+    }
+
+    @Test
+    public void testAbortTransaction() throws Throwable {
+        new ShardTestKit(getSystem()) {{
+            final TestActorRef<Shard> shard = TestActorRef.create(getSystem(),
+                    newShardProps().withDispatcher(Dispatchers.DefaultDispatcherId()), shardName());
+
+            waitUntilLeader(shard);
+
+            // Setup 2 simulated transactions with mock cohorts. The first one will be aborted.
+
+            String transactionID1 = "tx1";
+            MutableCompositeModification modification1 = new MutableCompositeModification();
+            DOMStoreThreePhaseCommitCohort cohort1 = mock(DOMStoreThreePhaseCommitCohort.class, "cohort1");
+            doReturn(Futures.immediateFuture(Boolean.TRUE)).when(cohort1).canCommit();
+            doReturn(Futures.immediateFuture(null)).when(cohort1).abort();
+
+            String transactionID2 = "tx2";
+            MutableCompositeModification modification2 = new MutableCompositeModification();
+            DOMStoreThreePhaseCommitCohort cohort2 = mock(DOMStoreThreePhaseCommitCohort.class, "cohort2");
+            doReturn(Futures.immediateFuture(Boolean.TRUE)).when(cohort2).canCommit();
+
+            FiniteDuration duration = duration("5 seconds");
+            final Timeout timeout = new Timeout(duration);
+
+            // Simulate the ForwardedReadyTransaction messages that would be sent
+            // by the ShardTransaction.
+
+            shard.tell(new ForwardedReadyTransaction(transactionID1, cohort1, modification1, true), getRef());
+            expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS);
+
+            shard.tell(new ForwardedReadyTransaction(transactionID2, cohort2, modification2, true), getRef());
+            expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS);
+
+            // Send the CanCommitTransaction message for the first Tx.
+
+            shard.tell(new CanCommitTransaction(transactionID1).toSerializable(), getRef());
+            CanCommitTransactionReply canCommitReply = CanCommitTransactionReply.fromSerializable(
+                    expectMsgClass(duration, CanCommitTransactionReply.SERIALIZABLE_CLASS));
+            assertEquals("Can commit", true, canCommitReply.getCanCommit());
+
+            // Send the CanCommitTransaction message for the 2nd Tx. This should get queued and
+            // processed after the first Tx completes.
+
+            Future<Object> canCommitFuture = Patterns.ask(shard,
+                    new CanCommitTransaction(transactionID2).toSerializable(), timeout);
+
+            // Send the AbortTransaction message for the first Tx. This should trigger the 2nd
+            // Tx to proceed.
+
+            shard.tell(new AbortTransaction(transactionID1).toSerializable(), getRef());
+            expectMsgClass(duration, AbortTransactionReply.SERIALIZABLE_CLASS);
+
+            // Wait for the 2nd Tx to complete the canCommit phase.
+
+            final CountDownLatch latch = new CountDownLatch(1);
+            canCommitFuture.onComplete(new OnComplete<Object>() {
+                @Override
+                public void onComplete(Throwable t, Object resp) {
+                    latch.countDown();
+                }
+            }, getSystem().dispatcher());
+
+            assertEquals("2nd CanCommit complete", true, latch.await(5, TimeUnit.SECONDS));
+
+            InOrder inOrder = inOrder(cohort1, cohort2);
+            inOrder.verify(cohort1).canCommit();
+            inOrder.verify(cohort2).canCommit();
         }};
     }
 
     @Test
     public void testCreateSnapshot() throws IOException, InterruptedException {
         new ShardTestKit(getSystem()) {{
-            final ActorRef subject = getSystem().actorOf(newShardProps(), "testCreateSnapshot");
+            final AtomicReference<CountDownLatch> latch = new AtomicReference<>(new CountDownLatch(1));
+            Creator<Shard> creator = new Creator<Shard>() {
+                @Override
+                public Shard create() throws Exception {
+                    return new Shard(IDENTIFIER, Collections.<ShardIdentifier,String>emptyMap(),
+                            dataStoreContext, SCHEMA_CONTEXT) {
+                        @Override
+                        public void saveSnapshot(Object snapshot) {
+                            super.saveSnapshot(snapshot);
+                            latch.get().countDown();
+                        }
+                    };
+                }
+            };
 
-            waitUntilLeader(subject);
+            TestActorRef<Shard> shard = TestActorRef.create(getSystem(),
+                    Props.create(new DelegatingShardCreator(creator)), "testCreateSnapshot");
 
-            subject.tell(new CaptureSnapshot(-1,-1,-1,-1), getRef());
+            waitUntilLeader(shard);
+
+            shard.tell(new CaptureSnapshot(-1,-1,-1,-1), getRef());
 
-            waitForLogMessage(Logging.Info.class, subject, "CaptureSnapshotReply received by actor");
+            assertEquals("Snapshot saved", true, latch.get().await(5, TimeUnit.SECONDS));
 
-            subject.tell(new CaptureSnapshot(-1,-1,-1,-1), getRef());
+            latch.set(new CountDownLatch(1));
+            shard.tell(new CaptureSnapshot(-1,-1,-1,-1), getRef());
 
-            waitForLogMessage(Logging.Info.class, subject, "CaptureSnapshotReply received by actor");
+            assertEquals("Snapshot saved", true, latch.get().await(5, TimeUnit.SECONDS));
         }};
     }
 
@@ -467,45 +1121,42 @@ public class ShardTest extends AbstractActorTest {
         };
     }
 
-    private static final class DelegatingShardCreator implements Creator<Shard> {
-        private final Creator<Shard> delegate;
+    private NormalizedNode<?,?> readStore(TestActorRef<Shard> shard, YangInstanceIdentifier id)
+            throws ExecutionException, InterruptedException {
+        DOMStoreReadTransaction transaction = shard.underlyingActor().getDataStore().newReadOnlyTransaction();
 
-        DelegatingShardCreator(Creator<Shard> delegate) {
-            this.delegate = delegate;
-        }
+        CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> future =
+            transaction.read(id);
 
-        @Override
-        public Shard create() throws Exception {
-            return delegate.create();
-        }
+        Optional<NormalizedNode<?, ?>> optional = future.get();
+        NormalizedNode<?, ?> node = optional.isPresent()? optional.get() : null;
+
+        transaction.close();
+
+        return node;
     }
 
-    private static class ShardTestKit extends JavaTestKit {
+    private void writeToStore(TestActorRef<Shard> shard, YangInstanceIdentifier id, NormalizedNode<?,?> node)
+        throws ExecutionException, InterruptedException {
+        DOMStoreWriteTransaction transaction = shard.underlyingActor().getDataStore().newWriteOnlyTransaction();
 
-        private ShardTestKit(ActorSystem actorSystem) {
-            super(actorSystem);
-        }
+        transaction.write(id, node);
 
-        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();
+        DOMStoreThreePhaseCommitCohort commitCohort = transaction.ready();
+        commitCohort.preCommit().get();
+        commitCohort.commit().get();
+    }
 
-            Assert.assertEquals(true, result);
+    private static final class DelegatingShardCreator implements Creator<Shard> {
+        private final Creator<Shard> delegate;
 
+        DelegatingShardCreator(Creator<Shard> delegate) {
+            this.delegate = delegate;
         }
 
-        protected void waitUntilLeader(ActorRef subject) {
-            waitForLogMessage(Logging.Info.class, subject,
-                    "Switching from state Candidate to Leader");
+        @Override
+        public Shard create() throws Exception {
+            return delegate.create();
         }
     }
 }
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTestKit.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTestKit.java
new file mode 100644 (file)
index 0000000..9a0e8f9
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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.cluster.datastore;
+
+import java.util.concurrent.TimeUnit;
+import org.junit.Assert;
+import org.opendaylight.controller.cluster.raft.client.messages.FindLeader;
+import org.opendaylight.controller.cluster.raft.client.messages.FindLeaderReply;
+import com.google.common.util.concurrent.Uninterruptibles;
+import scala.concurrent.Await;
+import scala.concurrent.Future;
+import scala.concurrent.duration.Duration;
+import akka.actor.ActorRef;
+import akka.actor.ActorSystem;
+import akka.pattern.Patterns;
+import akka.testkit.JavaTestKit;
+import akka.util.Timeout;
+
+class ShardTestKit extends JavaTestKit {
+
+    ShardTestKit(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);
+
+    }
+
+    protected void waitUntilLeader(ActorRef shard) {
+        for(int i = 0; i < 20 * 5; i++) {
+            Future<Object> future = Patterns.ask(shard, new FindLeader(), new Timeout(5, TimeUnit.SECONDS));
+            try {
+                FindLeaderReply resp = (FindLeaderReply)Await.result(future, Duration.create(5, TimeUnit.SECONDS));
+                if(resp.getLeaderActor() != null) {
+                    return;
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+
+            Uninterruptibles.sleepUninterruptibly(50, TimeUnit.MILLISECONDS);
+        }
+
+        Assert.fail("Leader not found for shard " + shard.path());
+    }
+}
\ No newline at end of file
index 869f47578711ea313181e4011444dc82ca35feaa..17731de5cd48918a1d03d04ec6dece68b9321e5a 100644 (file)
@@ -13,10 +13,8 @@ package org.opendaylight.controller.cluster.datastore;
 import akka.actor.ActorRef;
 import akka.actor.Props;
 import akka.testkit.TestActorRef;
-
 import com.google.common.util.concurrent.ListeningExecutorService;
 import com.google.common.util.concurrent.MoreExecutors;
-
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.opendaylight.controller.cluster.datastore.identifiers.ShardIdentifier;
@@ -30,11 +28,9 @@ import org.opendaylight.controller.protobuff.messages.transaction.ShardTransacti
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-
 import scala.concurrent.Await;
 import scala.concurrent.Future;
 import scala.concurrent.duration.Duration;
-
 import java.util.Collections;
 import java.util.concurrent.TimeUnit;
 
@@ -58,7 +54,7 @@ public class ShardTransactionFailureTest extends AbstractActorTest {
         ShardIdentifier.builder().memberName("member-1")
             .shardName("inventory").type("operational").build();
 
-    private final DatastoreContext datastoreContext = new DatastoreContext();
+    private final DatastoreContext datastoreContext = DatastoreContext.newBuilder().build();
 
     private final ShardStats shardStats = new ShardStats(SHARD_IDENTIFIER.toString(), "DataStore");
 
@@ -68,7 +64,8 @@ public class ShardTransactionFailureTest extends AbstractActorTest {
     }
 
     private ActorRef createShard(){
-        return getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP, new DatastoreContext(), TestModel.createTestContext()));
+        return getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP, datastoreContext,
+                TestModel.createTestContext()));
     }
 
     @Test(expected = ReadFailedException.class)
@@ -77,7 +74,7 @@ public class ShardTransactionFailureTest extends AbstractActorTest {
 
         final ActorRef shard = createShard();
         final Props props = ShardTransaction.props(store.newReadOnlyTransaction(), shard,
-                testSchemaContext, datastoreContext, shardStats);
+                testSchemaContext, datastoreContext, shardStats, "txn");
 
         final TestActorRef<ShardTransaction> subject = TestActorRef
             .create(getSystem(), props,
@@ -106,7 +103,7 @@ public class ShardTransactionFailureTest extends AbstractActorTest {
 
         final ActorRef shard = createShard();
         final Props props = ShardTransaction.props(store.newReadWriteTransaction(), shard,
-                testSchemaContext, datastoreContext, shardStats);
+                testSchemaContext, datastoreContext, shardStats, "txn");
 
         final TestActorRef<ShardTransaction> subject = TestActorRef
             .create(getSystem(), props,
@@ -135,7 +132,7 @@ public class ShardTransactionFailureTest extends AbstractActorTest {
 
         final ActorRef shard = createShard();
         final Props props = ShardTransaction.props(store.newReadWriteTransaction(), shard,
-                testSchemaContext, datastoreContext, shardStats);
+                testSchemaContext, datastoreContext, shardStats, "txn");
 
         final TestActorRef<ShardTransaction> subject = TestActorRef
             .create(getSystem(), props,
@@ -164,7 +161,7 @@ public class ShardTransactionFailureTest extends AbstractActorTest {
 
         final ActorRef shard = createShard();
         final Props props = ShardTransaction.props(store.newWriteOnlyTransaction(), shard,
-                testSchemaContext, datastoreContext, shardStats);
+                testSchemaContext, datastoreContext, shardStats, "txn");
 
         final TestActorRef<ShardTransaction> subject = TestActorRef
             .create(getSystem(), props,
@@ -196,7 +193,7 @@ public class ShardTransactionFailureTest extends AbstractActorTest {
 
         final ActorRef shard = createShard();
         final Props props = ShardTransaction.props(store.newReadWriteTransaction(), shard,
-                testSchemaContext, datastoreContext, shardStats);
+                testSchemaContext, datastoreContext, shardStats, "txn");
 
         final TestActorRef<ShardTransaction> subject = TestActorRef
             .create(getSystem(), props,
@@ -233,7 +230,7 @@ public class ShardTransactionFailureTest extends AbstractActorTest {
 
         final ActorRef shard = createShard();
         final Props props = ShardTransaction.props(store.newReadWriteTransaction(), shard,
-                testSchemaContext, datastoreContext, shardStats);
+                testSchemaContext, datastoreContext, shardStats, "txn");
 
         final TestActorRef<ShardTransaction> subject = TestActorRef
             .create(getSystem(), props, "testNegativeMergeTransactionReady");
@@ -265,7 +262,7 @@ public class ShardTransactionFailureTest extends AbstractActorTest {
 
         final ActorRef shard = createShard();
         final Props props = ShardTransaction.props(store.newReadWriteTransaction(), shard,
-                testSchemaContext, datastoreContext, shardStats);
+                testSchemaContext, datastoreContext, shardStats, "txn");
 
         final TestActorRef<ShardTransaction> subject = TestActorRef
             .create(getSystem(), props,
index 3f31591c79c4f7d3aa6dff45f518c2f8d38726e0..711f3d7a72a16b615224246e07e3adb750b7cff6 100644 (file)
@@ -5,12 +5,11 @@ import akka.actor.Props;
 import akka.actor.Terminated;
 import akka.testkit.JavaTestKit;
 import akka.testkit.TestActorRef;
-
 import com.google.common.util.concurrent.ListeningExecutorService;
 import com.google.common.util.concurrent.MoreExecutors;
-
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.opendaylight.controller.cluster.datastore.ShardWriteTransaction.GetCompositeModificationReply;
 import org.opendaylight.controller.cluster.datastore.exceptions.UnknownMessageException;
 import org.opendaylight.controller.cluster.datastore.identifiers.ShardIdentifier;
 import org.opendaylight.controller.cluster.datastore.jmx.mbeans.shard.ShardStats;
@@ -35,17 +34,16 @@ import org.opendaylight.controller.cluster.datastore.modification.Modification;
 import org.opendaylight.controller.cluster.datastore.modification.WriteModification;
 import org.opendaylight.controller.md.cluster.datastore.model.TestModel;
 import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore;
-import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStoreConfigProperties;
+import org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionMessages;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-
 import scala.concurrent.duration.Duration;
-
 import java.util.Collections;
 import java.util.concurrent.TimeUnit;
-
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 public class ShardTransactionTest extends AbstractActorTest {
@@ -61,7 +59,7 @@ public class ShardTransactionTest extends AbstractActorTest {
         ShardIdentifier.builder().memberName("member-1")
             .shardName("inventory").type("config").build();
 
-    private DatastoreContext datastoreContext = new DatastoreContext();
+    private DatastoreContext datastoreContext = DatastoreContext.newBuilder().build();
 
     private final ShardStats shardStats = new ShardStats(SHARD_IDENTIFIER.toString(), "DataStore");
 
@@ -72,48 +70,42 @@ public class ShardTransactionTest extends AbstractActorTest {
 
     private ActorRef createShard(){
         return getSystem().actorOf(Shard.props(SHARD_IDENTIFIER,
-            Collections.EMPTY_MAP, new DatastoreContext(), TestModel.createTestContext()));
+            Collections.EMPTY_MAP, datastoreContext, TestModel.createTestContext()));
     }
 
     @Test
     public void testOnReceiveReadData() throws Exception {
         new JavaTestKit(getSystem()) {{
             final ActorRef shard = createShard();
-            final Props props = ShardTransaction.props(store.newReadOnlyTransaction(), shard,
-                    testSchemaContext, datastoreContext, shardStats);
-            final ActorRef subject = getSystem().actorOf(props, "testReadData");
+            Props props = ShardTransaction.props(store.newReadOnlyTransaction(), shard,
+                    testSchemaContext, datastoreContext, shardStats, "txn");
 
-            new Within(duration("1 seconds")) {
-                @Override
-                protected void run() {
-
-                    subject.tell(
-                        new ReadData(YangInstanceIdentifier.builder().build()).toSerializable(),
-                        getRef());
-
-                    final String out = new ExpectMsg<String>(duration("1 seconds"), "match hint") {
-                        // do not put code outside this method, will run afterwards
-                        @Override
-                        protected String match(Object in) {
-                            if (in.getClass().equals(ReadDataReply.SERIALIZABLE_CLASS)) {
-                              if (ReadDataReply.fromSerializable(testSchemaContext,YangInstanceIdentifier.builder().build(), in)
-                                  .getNormalizedNode()!= null) {
-                                    return "match";
-                                }
-                                return null;
-                            } else {
-                                throw noMatch();
-                            }
-                        }
-                    }.get(); // this extracts the received message
-
-                    assertEquals("match", out);
-
-                    expectNoMsg();
-                }
+            testOnReceiveReadData(getSystem().actorOf(props, "testReadDataRO"));
+
+            props = ShardTransaction.props(store.newReadWriteTransaction(), shard,
+                    testSchemaContext, datastoreContext, shardStats, "txn");
+
+            testOnReceiveReadData(getSystem().actorOf(props, "testReadDataRW"));
+        }
 
+        private void testOnReceiveReadData(final ActorRef subject) {
+            //serialized read
+            subject.tell(new ReadData(YangInstanceIdentifier.builder().build()).toSerializable(),
+                getRef());
 
-            };
+            ShardTransactionMessages.ReadDataReply replySerialized =
+                expectMsgClass(duration("5 seconds"), ReadDataReply.SERIALIZABLE_CLASS);
+
+            assertNotNull(ReadDataReply.fromSerializable(
+                testSchemaContext,YangInstanceIdentifier.builder().build(), replySerialized)
+                .getNormalizedNode());
+
+            // unserialized read
+            subject.tell(new ReadData(YangInstanceIdentifier.builder().build()),getRef());
+
+            ReadDataReply reply = expectMsgClass(duration("5 seconds"), ReadDataReply.class);
+
+            assertNotNull(reply.getNormalizedNode());
         }};
     }
 
@@ -121,42 +113,35 @@ public class ShardTransactionTest extends AbstractActorTest {
     public void testOnReceiveReadDataWhenDataNotFound() throws Exception {
         new JavaTestKit(getSystem()) {{
             final ActorRef shard = createShard();
-            final Props props = ShardTransaction.props( store.newReadOnlyTransaction(), shard,
-                    testSchemaContext, datastoreContext, shardStats);
-            final ActorRef subject = getSystem().actorOf(props, "testReadDataWhenDataNotFound");
+            Props props = ShardTransaction.props( store.newReadOnlyTransaction(), shard,
+                    testSchemaContext, datastoreContext, shardStats, "txn");
 
-            new Within(duration("1 seconds")) {
-                @Override
-                protected void run() {
-
-                    subject.tell(
-                        new ReadData(TestModel.TEST_PATH).toSerializable(),
-                        getRef());
-
-                    final String out = new ExpectMsg<String>(duration("1 seconds"), "match hint") {
-                        // do not put code outside this method, will run afterwards
-                        @Override
-                        protected String match(Object in) {
-                            if (in.getClass().equals(ReadDataReply.SERIALIZABLE_CLASS)) {
-                                if (ReadDataReply.fromSerializable(testSchemaContext,TestModel.TEST_PATH, in)
-                                    .getNormalizedNode()
-                                    == null) {
-                                    return "match";
-                                }
-                                return null;
-                            } else {
-                                throw noMatch();
-                            }
-                        }
-                    }.get(); // this extracts the received message
-
-                    assertEquals("match", out);
-
-                    expectNoMsg();
-                }
+            testOnReceiveReadDataWhenDataNotFound(getSystem().actorOf(
+                    props, "testReadDataWhenDataNotFoundRO"));
+
+            props = ShardTransaction.props( store.newReadWriteTransaction(), shard,
+                    testSchemaContext, datastoreContext, shardStats, "txn");
+
+            testOnReceiveReadDataWhenDataNotFound(getSystem().actorOf(
+                    props, "testReadDataWhenDataNotFoundRW"));
+        }
 
+        private void testOnReceiveReadDataWhenDataNotFound(final ActorRef subject) {
+            // serialized read
+            subject.tell(new ReadData(TestModel.TEST_PATH).toSerializable(), getRef());
 
-            };
+            ShardTransactionMessages.ReadDataReply replySerialized =
+                expectMsgClass(duration("5 seconds"), ReadDataReply.SERIALIZABLE_CLASS);
+
+            assertTrue(ReadDataReply.fromSerializable(
+                testSchemaContext, TestModel.TEST_PATH, replySerialized).getNormalizedNode() == null);
+
+            // unserialized read
+            subject.tell(new ReadData(TestModel.TEST_PATH),getRef());
+
+            ReadDataReply reply = expectMsgClass(duration("5 seconds"), ReadDataReply.class);
+
+            assertTrue(reply.getNormalizedNode() == null);
         }};
     }
 
@@ -164,41 +149,32 @@ public class ShardTransactionTest extends AbstractActorTest {
     public void testOnReceiveDataExistsPositive() throws Exception {
         new JavaTestKit(getSystem()) {{
             final ActorRef shard = createShard();
-            final Props props = ShardTransaction.props(store.newReadOnlyTransaction(), shard,
-                    testSchemaContext, datastoreContext, shardStats);
-            final ActorRef subject = getSystem().actorOf(props, "testDataExistsPositive");
+            Props props = ShardTransaction.props(store.newReadOnlyTransaction(), shard,
+                    testSchemaContext, datastoreContext, shardStats, "txn");
 
-            new Within(duration("1 seconds")) {
-                @Override
-                protected void run() {
-
-                    subject.tell(
-                        new DataExists(YangInstanceIdentifier.builder().build()).toSerializable(),
-                        getRef());
-
-                    final String out = new ExpectMsg<String>(duration("1 seconds"), "match hint") {
-                        // do not put code outside this method, will run afterwards
-                        @Override
-                        protected String match(Object in) {
-                            if (in.getClass().equals(DataExistsReply.SERIALIZABLE_CLASS)) {
-                                if (DataExistsReply.fromSerializable(in)
-                                    .exists()) {
-                                    return "match";
-                                }
-                                return null;
-                            } else {
-                                throw noMatch();
-                            }
-                        }
-                    }.get(); // this extracts the received message
-
-                    assertEquals("match", out);
-
-                    expectNoMsg();
-                }
+            testOnReceiveDataExistsPositive(getSystem().actorOf(props, "testDataExistsPositiveRO"));
+
+            props = ShardTransaction.props(store.newReadWriteTransaction(), shard,
+                    testSchemaContext, datastoreContext, shardStats, "txn");
+
+            testOnReceiveDataExistsPositive(getSystem().actorOf(props, "testDataExistsPositiveRW"));
+        }
 
+        private void testOnReceiveDataExistsPositive(final ActorRef subject) {
+            subject.tell(new DataExists(YangInstanceIdentifier.builder().build()).toSerializable(),
+                getRef());
 
-            };
+            ShardTransactionMessages.DataExistsReply replySerialized =
+                expectMsgClass(duration("5 seconds"), ShardTransactionMessages.DataExistsReply.class);
+
+            assertTrue(DataExistsReply.fromSerializable(replySerialized).exists());
+
+            // unserialized read
+            subject.tell(new DataExists(YangInstanceIdentifier.builder().build()),getRef());
+
+            DataExistsReply reply = expectMsgClass(duration("5 seconds"), DataExistsReply.class);
+
+            assertTrue(reply.exists());
         }};
     }
 
@@ -206,76 +182,44 @@ public class ShardTransactionTest extends AbstractActorTest {
     public void testOnReceiveDataExistsNegative() throws Exception {
         new JavaTestKit(getSystem()) {{
             final ActorRef shard = createShard();
-            final Props props = ShardTransaction.props(store.newReadOnlyTransaction(), shard,
-                    testSchemaContext, datastoreContext, shardStats);
-            final ActorRef subject = getSystem().actorOf(props, "testDataExistsNegative");
+            Props props = ShardTransaction.props(store.newReadOnlyTransaction(), shard,
+                    testSchemaContext, datastoreContext, shardStats, "txn");
 
-            new Within(duration("1 seconds")) {
-                @Override
-                protected void run() {
-
-                    subject.tell(
-                        new DataExists(TestModel.TEST_PATH).toSerializable(),
-                        getRef());
-
-                    final String out = new ExpectMsg<String>(duration("1 seconds"), "match hint") {
-                        // do not put code outside this method, will run afterwards
-                        @Override
-                        protected String match(Object in) {
-                            if (in.getClass().equals(DataExistsReply.SERIALIZABLE_CLASS)) {
-                                if (!DataExistsReply.fromSerializable(in)
-                                    .exists()) {
-                                    return "match";
-                                }
-                                return null;
-                            } else {
-                                throw noMatch();
-                            }
-                        }
-                    }.get(); // this extracts the received message
-
-                    assertEquals("match", out);
-
-                    expectNoMsg();
-                }
+            testOnReceiveDataExistsNegative(getSystem().actorOf(props, "testDataExistsNegativeRO"));
+
+            props = ShardTransaction.props(store.newReadWriteTransaction(), shard,
+                    testSchemaContext, datastoreContext, shardStats, "txn");
+
+            testOnReceiveDataExistsNegative(getSystem().actorOf(props, "testDataExistsNegativeRW"));
+        }
 
+        private void testOnReceiveDataExistsNegative(final ActorRef subject) {
+            subject.tell(new DataExists(TestModel.TEST_PATH).toSerializable(), getRef());
 
-            };
+            ShardTransactionMessages.DataExistsReply replySerialized =
+                expectMsgClass(duration("5 seconds"), ShardTransactionMessages.DataExistsReply.class);
+
+            assertFalse(DataExistsReply.fromSerializable(replySerialized).exists());
+
+            // unserialized read
+            subject.tell(new DataExists(TestModel.TEST_PATH),getRef());
+
+            DataExistsReply reply = expectMsgClass(duration("5 seconds"), DataExistsReply.class);
+
+            assertFalse(reply.exists());
         }};
     }
 
     private void assertModification(final ActorRef subject,
         final Class<? extends Modification> modificationType) {
         new JavaTestKit(getSystem()) {{
-            new Within(duration("1 seconds")) {
-                @Override
-                protected void run() {
-                    subject
-                        .tell(new ShardTransaction.GetCompositedModification(),
-                            getRef());
-
-                    final CompositeModification compositeModification =
-                        new ExpectMsg<CompositeModification>(duration("1 seconds"), "match hint") {
-                            // do not put code outside this method, will run afterwards
-                            @Override
-                            protected CompositeModification match(Object in) {
-                                if (in instanceof ShardTransaction.GetCompositeModificationReply) {
-                                    return ((ShardTransaction.GetCompositeModificationReply) in)
-                                        .getModification();
-                                } else {
-                                    throw noMatch();
-                                }
-                            }
-                        }.get(); // this extracts the received message
-
-                    assertTrue(
-                        compositeModification.getModifications().size() == 1);
-                    assertEquals(modificationType,
-                        compositeModification.getModifications().get(0)
-                            .getClass());
+            subject.tell(new ShardWriteTransaction.GetCompositedModification(), getRef());
 
-                }
-            };
+            CompositeModification compositeModification = expectMsgClass(duration("3 seconds"),
+                    GetCompositeModificationReply.class).getModification();
+
+            assertTrue(compositeModification.getModifications().size() == 1);
+            assertEquals(modificationType, compositeModification.getModifications().get(0).getClass());
         }};
     }
 
@@ -284,38 +228,26 @@ public class ShardTransactionTest extends AbstractActorTest {
         new JavaTestKit(getSystem()) {{
             final ActorRef shard = createShard();
             final Props props = ShardTransaction.props(store.newWriteOnlyTransaction(), shard,
-                    testSchemaContext, datastoreContext, shardStats);
+                    testSchemaContext, datastoreContext, shardStats, "txn");
             final ActorRef subject =
                 getSystem().actorOf(props, "testWriteData");
 
-            new Within(duration("1 seconds")) {
-                @Override
-                protected void run() {
-
-                    subject.tell(new WriteData(TestModel.TEST_PATH,
-                        ImmutableNodes.containerNode(TestModel.TEST_QNAME), TestModel.createTestContext()).toSerializable(),
-                        getRef());
-
-                    final String out = new ExpectMsg<String>(duration("1 seconds"), "match hint") {
-                        // do not put code outside this method, will run afterwards
-                        @Override
-                        protected String match(Object in) {
-                            if (in.getClass().equals(WriteDataReply.SERIALIZABLE_CLASS)) {
-                                return "match";
-                            } else {
-                                throw noMatch();
-                            }
-                        }
-                    }.get(); // this extracts the received message
-
-                    assertEquals("match", out);
-
-                    assertModification(subject, WriteModification.class);
-                    expectNoMsg();
-                }
+            subject.tell(new WriteData(TestModel.TEST_PATH,
+                ImmutableNodes.containerNode(TestModel.TEST_QNAME), TestModel.createTestContext()).toSerializable(),
+                getRef());
 
+            ShardTransactionMessages.WriteDataReply replySerialized =
+                expectMsgClass(duration("5 seconds"), ShardTransactionMessages.WriteDataReply.class);
 
-            };
+            assertModification(subject, WriteModification.class);
+
+            //unserialized write
+            subject.tell(new WriteData(TestModel.TEST_PATH,
+                ImmutableNodes.containerNode(TestModel.TEST_QNAME),
+                TestModel.createTestContext()),
+                getRef());
+
+            expectMsgClass(duration("5 seconds"), WriteDataReply.class);
         }};
     }
 
@@ -324,39 +256,25 @@ public class ShardTransactionTest extends AbstractActorTest {
         new JavaTestKit(getSystem()) {{
             final ActorRef shard = createShard();
             final Props props = ShardTransaction.props(store.newReadWriteTransaction(), shard,
-                    testSchemaContext, datastoreContext, shardStats);
+                    testSchemaContext, datastoreContext, shardStats, "txn");
             final ActorRef subject =
                 getSystem().actorOf(props, "testMergeData");
 
-            new Within(duration("1 seconds")) {
-                @Override
-                protected void run() {
-
-                    subject.tell(new MergeData(TestModel.TEST_PATH,
-                        ImmutableNodes.containerNode(TestModel.TEST_QNAME), testSchemaContext).toSerializable(),
-                        getRef());
+            subject.tell(new MergeData(TestModel.TEST_PATH,
+                ImmutableNodes.containerNode(TestModel.TEST_QNAME), testSchemaContext).toSerializable(),
+                getRef());
 
-                    final String out = new ExpectMsg<String>(duration("500 milliseconds"), "match hint") {
-                        // do not put code outside this method, will run afterwards
-                        @Override
-                        protected String match(Object in) {
-                            if (in.getClass().equals(MergeDataReply.SERIALIZABLE_CLASS)) {
-                                return "match";
-                            } else {
-                                throw noMatch();
-                            }
-                        }
-                    }.get(); // this extracts the received message
+            ShardTransactionMessages.MergeDataReply replySerialized =
+                expectMsgClass(duration("5 seconds"), ShardTransactionMessages.MergeDataReply.class);
 
-                    assertEquals("match", out);
+            assertModification(subject, MergeModification.class);
 
-                    assertModification(subject, MergeModification.class);
+            //unserialized merge
+            subject.tell(new MergeData(TestModel.TEST_PATH,
+                ImmutableNodes.containerNode(TestModel.TEST_QNAME), testSchemaContext),
+                getRef());
 
-                    expectNoMsg();
-                }
-
-
-            };
+            expectMsgClass(duration("5 seconds"), MergeDataReply.class);
         }};
     }
 
@@ -365,36 +283,21 @@ public class ShardTransactionTest extends AbstractActorTest {
         new JavaTestKit(getSystem()) {{
             final ActorRef shard = createShard();
             final Props props = ShardTransaction.props( store.newWriteOnlyTransaction(), shard,
-                    testSchemaContext, datastoreContext, shardStats);
+                    testSchemaContext, datastoreContext, shardStats, "txn");
             final ActorRef subject =
                 getSystem().actorOf(props, "testDeleteData");
 
-            new Within(duration("1 seconds")) {
-                @Override
-                protected void run() {
-
-                    subject.tell(new DeleteData(TestModel.TEST_PATH).toSerializable(), getRef());
-
-                    final String out = new ExpectMsg<String>(duration("1 seconds"), "match hint") {
-                        // do not put code outside this method, will run afterwards
-                        @Override
-                        protected String match(Object in) {
-                            if (in.getClass().equals(DeleteDataReply.SERIALIZABLE_CLASS)) {
-                                return "match";
-                            } else {
-                                throw noMatch();
-                            }
-                        }
-                    }.get(); // this extracts the received message
-
-                    assertEquals("match", out);
-
-                    assertModification(subject, DeleteModification.class);
-                    expectNoMsg();
-                }
+            subject.tell(new DeleteData(TestModel.TEST_PATH).toSerializable(), getRef());
+
+            ShardTransactionMessages.DeleteDataReply replySerialized =
+                expectMsgClass(duration("5 seconds"), ShardTransactionMessages.DeleteDataReply.class);
 
+            assertModification(subject, DeleteModification.class);
 
-            };
+            //unserialized merge
+            subject.tell(new DeleteData(TestModel.TEST_PATH), getRef());
+
+            expectMsgClass(duration("5 seconds"), DeleteDataReply.class);
         }};
     }
 
@@ -404,87 +307,45 @@ public class ShardTransactionTest extends AbstractActorTest {
         new JavaTestKit(getSystem()) {{
             final ActorRef shard = createShard();
             final Props props = ShardTransaction.props( store.newReadWriteTransaction(), shard,
-                    testSchemaContext, datastoreContext, shardStats);
+                    testSchemaContext, datastoreContext, shardStats, "txn");
             final ActorRef subject =
                 getSystem().actorOf(props, "testReadyTransaction");
 
-            new Within(duration("1 seconds")) {
-                @Override
-                protected void run() {
-
-                    subject.tell(new ReadyTransaction().toSerializable(), getRef());
-
-                    final String out = new ExpectMsg<String>(duration("1 seconds"), "match hint") {
-                        // do not put code outside this method, will run afterwards
-                        @Override
-                        protected String match(Object in) {
-                            if (in.getClass().equals(ReadyTransactionReply.SERIALIZABLE_CLASS)) {
-                                return "match";
-                            } else {
-                                throw noMatch();
-                            }
-                        }
-                    }.get(); // this extracts the received message
+            subject.tell(new ReadyTransaction().toSerializable(), getRef());
 
-                    assertEquals("match", out);
+            expectMsgClass(duration("5 seconds"), ReadyTransactionReply.SERIALIZABLE_CLASS);
+        }};
 
-                    expectNoMsg();
-                }
+        // test
+        new JavaTestKit(getSystem()) {{
+            final ActorRef shard = createShard();
+            final Props props = ShardTransaction.props( store.newReadWriteTransaction(), shard,
+                testSchemaContext, datastoreContext, shardStats, "txn");
+            final ActorRef subject =
+                getSystem().actorOf(props, "testReadyTransaction2");
 
+            subject.tell(new ReadyTransaction(), getRef());
 
-            };
+            expectMsgClass(duration("5 seconds"), ReadyTransactionReply.class);
         }};
 
     }
 
+    @SuppressWarnings("unchecked")
     @Test
     public void testOnReceiveCloseTransaction() throws Exception {
         new JavaTestKit(getSystem()) {{
             final ActorRef shard = createShard();
             final Props props = ShardTransaction.props(store.newReadWriteTransaction(), shard,
-                    testSchemaContext, datastoreContext, shardStats);
-            final ActorRef subject =
-                getSystem().actorOf(props, "testCloseTransaction");
+                    testSchemaContext, datastoreContext, shardStats, "txn");
+            final ActorRef subject = getSystem().actorOf(props, "testCloseTransaction");
 
             watch(subject);
 
-            new Within(duration("6 seconds")) {
-                @Override
-                protected void run() {
-
-                    subject.tell(new CloseTransaction().toSerializable(), getRef());
-
-                    final String out = new ExpectMsg<String>(duration("3 seconds"), "match hint") {
-                        // do not put code outside this method, will run afterwards
-                        @Override
-                        protected String match(Object in) {
-                            System.out.println("!!!IN match 1: "+(in!=null?in.getClass():"NULL"));
-                            if (in.getClass().equals(CloseTransactionReply.SERIALIZABLE_CLASS)) {
-                                return "match";
-                            } else {
-                                throw noMatch();
-                            }
-                        }
-                    }.get(); // this extracts the received message
-
-                    assertEquals("match", out);
-
-                    final String termination = new ExpectMsg<String>(duration("3 seconds"), "match hint") {
-                        // do not put code outside this method, will run afterwards
-                        @Override
-                        protected String match(Object in) {
-                            System.out.println("!!!IN match 2: "+(in!=null?in.getClass():"NULL"));
-                            if (in instanceof Terminated) {
-                                return "match";
-                            } else {
-                                throw noMatch();
-                            }
-                        }
-                    }.get(); // this extracts the received message
-
-                    assertEquals("match", termination);
-                }
-            };
+            subject.tell(new CloseTransaction().toSerializable(), getRef());
+
+            expectMsgClass(duration("3 seconds"), CloseTransactionReply.SERIALIZABLE_CLASS);
+            expectMsgClass(duration("3 seconds"), Terminated.class);
         }};
     }
 
@@ -492,7 +353,7 @@ public class ShardTransactionTest extends AbstractActorTest {
     public void testNegativePerformingWriteOperationOnReadTransaction() throws Exception {
         final ActorRef shard = createShard();
         final Props props = ShardTransaction.props(store.newReadOnlyTransaction(), shard,
-                testSchemaContext, datastoreContext, shardStats);
+                testSchemaContext, datastoreContext, shardStats, "txn");
         final TestActorRef subject = TestActorRef.apply(props,getSystem());
 
         subject.receive(new DeleteData(TestModel.TEST_PATH).toSerializable(), ActorRef.noSender());
@@ -501,14 +362,13 @@ public class ShardTransactionTest extends AbstractActorTest {
     @Test
     public void testShardTransactionInactivity() {
 
-        datastoreContext = new DatastoreContext("Test",
-                InMemoryDOMDataStoreConfigProperties.getDefault(),
-                Duration.create(500, TimeUnit.MILLISECONDS), 5, 1000, 1000, 500);
+        datastoreContext = DatastoreContext.newBuilder().shardTransactionIdleTimeout(
+                Duration.create(500, TimeUnit.MILLISECONDS)).build();
 
         new JavaTestKit(getSystem()) {{
             final ActorRef shard = createShard();
             final Props props = ShardTransaction.props(store.newReadWriteTransaction(), shard,
-                    testSchemaContext, datastoreContext, shardStats);
+                    testSchemaContext, datastoreContext, shardStats, "txn");
             final ActorRef subject =
                 getSystem().actorOf(props, "testShardTransactionInactivity");
 
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortFailureTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortFailureTest.java
deleted file mode 100644 (file)
index 4e4c34b..0000000
+++ /dev/null
@@ -1,228 +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.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;
-import com.google.common.util.concurrent.MoreExecutors;
-
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.mockito.Mockito;
-import org.opendaylight.controller.cluster.datastore.identifiers.ShardIdentifier;
-import org.opendaylight.controller.cluster.datastore.jmx.mbeans.shard.ShardStats;
-import org.opendaylight.controller.cluster.datastore.messages.ForwardedCommitTransaction;
-import org.opendaylight.controller.cluster.datastore.modification.CompositeModification;
-import org.opendaylight.controller.cluster.datastore.modification.Modification;
-import org.opendaylight.controller.md.cluster.datastore.model.TestModel;
-import org.opendaylight.controller.md.sal.common.api.data.OptimisticLockFailedException;
-import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore;
-import org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages;
-import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages;
-import org.opendaylight.controller.protobuff.messages.persistent.PersistentMessages;
-import org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionMessages;
-import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
-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.Collections;
-import java.util.concurrent.TimeUnit;
-
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.when;
-
-
-public class ThreePhaseCommitCohortFailureTest extends AbstractActorTest {
-
-    private static ListeningExecutorService storeExecutor =
-        MoreExecutors.listeningDecorator(MoreExecutors.sameThreadExecutor());
-
-    private static final InMemoryDOMDataStore store =
-        new InMemoryDOMDataStore("OPER", storeExecutor,
-            MoreExecutors.sameThreadExecutor());
-
-    private static final SchemaContext testSchemaContext =
-        TestModel.createTestContext();
-
-    private static final ShardIdentifier SHARD_IDENTIFIER =
-        ShardIdentifier.builder().memberName("member-1")
-            .shardName("inventory").type("config").build();
-
-    private final DatastoreContext datastoreContext = new DatastoreContext();
-
-    private final ShardStats shardStats = new ShardStats(SHARD_IDENTIFIER.toString(), "DataStore");
-
-    @BeforeClass
-    public static void staticSetup() {
-        store.onGlobalContextUpdated(testSchemaContext);
-    }
-
-    private final FiniteDuration ASK_RESULT_DURATION = Duration.create(5000, TimeUnit.MILLISECONDS);
-
-    private ActorRef createShard(){
-        return getSystem().actorOf(Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP, datastoreContext, TestModel.createTestContext()));
-    }
-
-    @Test(expected = TestException.class)
-    public void testNegativeAbortResultsInException() throws Exception {
-
-        final ActorRef shard = createShard();
-        final DOMStoreThreePhaseCommitCohort mockCohort = Mockito
-            .mock(DOMStoreThreePhaseCommitCohort.class);
-        final CompositeModification mockComposite =
-            Mockito.mock(CompositeModification.class);
-        final Props props =
-            ThreePhaseCommitCohort.props(mockCohort, shard, mockComposite, shardStats);
-
-        final TestActorRef<ThreePhaseCommitCohort> subject = TestActorRef
-            .create(getSystem(), props,
-                "testNegativeAbortResultsInException");
-
-        when(mockCohort.abort()).thenReturn(
-            Futures.<Void>immediateFailedFuture(new TestException()));
-
-        Future<Object> future =
-            akka.pattern.Patterns.ask(subject,
-                ThreePhaseCommitCohortMessages.AbortTransaction.newBuilder()
-                    .build(), 3000);
-        assertTrue(future.isCompleted());
-
-        Await.result(future, ASK_RESULT_DURATION);
-    }
-
-
-    @Test(expected = OptimisticLockFailedException.class)
-    public void testNegativeCanCommitResultsInException() throws Exception {
-
-        final ActorRef shard = createShard();
-        final DOMStoreThreePhaseCommitCohort mockCohort = Mockito
-            .mock(DOMStoreThreePhaseCommitCohort.class);
-        final CompositeModification mockComposite =
-            Mockito.mock(CompositeModification.class);
-        final Props props =
-            ThreePhaseCommitCohort.props(mockCohort, shard, mockComposite, shardStats);
-
-        final TestActorRef<ThreePhaseCommitCohort> subject = TestActorRef
-            .create(getSystem(), props,
-                "testNegativeCanCommitResultsInException");
-
-        when(mockCohort.canCommit()).thenReturn(
-            Futures
-                .<Boolean>immediateFailedFuture(
-                    new OptimisticLockFailedException("some exception")));
-
-        Future<Object> future =
-            akka.pattern.Patterns.ask(subject,
-                ThreePhaseCommitCohortMessages.CanCommitTransaction.newBuilder()
-                    .build(), 3000);
-
-
-        Await.result(future, ASK_RESULT_DURATION);
-
-    }
-
-
-    @Test(expected = TestException.class)
-    public void testNegativePreCommitResultsInException() throws Exception {
-
-        final ActorRef shard = createShard();
-        final DOMStoreThreePhaseCommitCohort mockCohort = Mockito
-            .mock(DOMStoreThreePhaseCommitCohort.class);
-        final CompositeModification mockComposite =
-            Mockito.mock(CompositeModification.class);
-        final Props props =
-            ThreePhaseCommitCohort.props(mockCohort, shard, mockComposite, shardStats);
-
-        final TestActorRef<ThreePhaseCommitCohort> subject = TestActorRef
-            .create(getSystem(), props,
-                "testNegativePreCommitResultsInException");
-
-        when(mockCohort.preCommit()).thenReturn(
-            Futures
-                .<Void>immediateFailedFuture(
-                    new TestException()));
-
-        Future<Object> future =
-            akka.pattern.Patterns.ask(subject,
-                ThreePhaseCommitCohortMessages.PreCommitTransaction.newBuilder()
-                    .build(), 3000);
-
-        Await.result(future, ASK_RESULT_DURATION);
-
-    }
-
-    @Test(expected = TestException.class)
-    public void testNegativeCommitResultsInException() throws Exception {
-
-        final TestActorRef<Shard> subject = TestActorRef.create(getSystem(),
-                Shard.props(SHARD_IDENTIFIER, Collections.EMPTY_MAP, datastoreContext, TestModel.createTestContext()),
-                "testNegativeCommitResultsInException");
-
-        final ActorRef shardTransaction =
-            getSystem().actorOf(ShardTransaction.props(store.newReadWriteTransaction(), subject,
-                    testSchemaContext, datastoreContext, shardStats));
-
-        ShardTransactionMessages.WriteData writeData =
-            ShardTransactionMessages.WriteData.newBuilder()
-                .setInstanceIdentifierPathArguments(
-                    NormalizedNodeMessages.InstanceIdentifier.newBuilder()
-                        .build()).setNormalizedNode(
-                NormalizedNodeMessages.Node.newBuilder().build()
-
-            ).build();
-
-        Timeout askTimeout = new Timeout(ASK_RESULT_DURATION);
-
-        //This is done so that Modification list is updated which is used during commit
-        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, askTimeout);
-
-        //but when the message is sent it will have the MockCommit object
-        //so that we can simulate throwing of exception
-        ForwardedCommitTransaction mockForwardCommitTransaction =
-            Mockito.mock(ForwardedCommitTransaction.class);
-        DOMStoreThreePhaseCommitCohort mockThreePhaseCommitTransaction =
-            Mockito.mock(DOMStoreThreePhaseCommitCohort.class);
-        when(mockForwardCommitTransaction.getCohort())
-            .thenReturn(mockThreePhaseCommitTransaction);
-        when(mockThreePhaseCommitTransaction.commit()).thenReturn(Futures
-            .<Void>immediateFailedFuture(
-                new TestException()));
-        Modification mockModification = Mockito.mock(
-            Modification.class);
-        when(mockForwardCommitTransaction.getModification())
-            .thenReturn(mockModification);
-
-        when(mockModification.toSerializable()).thenReturn(
-            PersistentMessages.CompositeModification.newBuilder().build());
-
-        future = akka.pattern.Patterns.ask(subject, mockForwardCommitTransaction, askTimeout);
-        Await.result(future, ASK_RESULT_DURATION);
-    }
-
-    private class TestException extends Exception {
-    }
-}
index 1cd0f85fa1917057f77144f23009a7edb65c0150..46060dda2a9bdd1cf1ec94e98d24c53ec97ed5a3 100644 (file)
@@ -4,19 +4,8 @@ import akka.actor.ActorPath;
 import akka.actor.ActorSelection;
 import akka.actor.Props;
 import akka.dispatch.Futures;
-
 import com.google.common.collect.Lists;
 import com.google.common.util.concurrent.ListenableFuture;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.isA;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.times;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
@@ -33,13 +22,20 @@ import org.opendaylight.controller.cluster.datastore.messages.PreCommitTransacti
 import org.opendaylight.controller.cluster.datastore.messages.SerializableMessage;
 import org.opendaylight.controller.cluster.datastore.utils.ActorContext;
 import org.opendaylight.controller.cluster.datastore.utils.DoNothingActor;
-
 import scala.concurrent.Future;
 
 import java.util.List;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.isA;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
 public class ThreePhaseCommitCohortProxyTest extends AbstractActorTest {
 
     @SuppressWarnings("serial")
@@ -56,28 +52,28 @@ public class ThreePhaseCommitCohortProxyTest extends AbstractActorTest {
         doReturn(getSystem()).when(actorContext).getActorSystem();
     }
 
-    private Future<ActorPath> newCohortPath() {
+    private Future<ActorSelection> newCohort() {
         ActorPath path = getSystem().actorOf(Props.create(DoNothingActor.class)).path();
-        doReturn(mock(ActorSelection.class)).when(actorContext).actorSelection(path);
-        return Futures.successful(path);
+        ActorSelection actorSelection = getSystem().actorSelection(path);
+        return Futures.successful(actorSelection);
     }
 
     private final ThreePhaseCommitCohortProxy setupProxy(int nCohorts) throws Exception {
-        List<Future<ActorPath>> cohortPathFutures = Lists.newArrayList();
+        List<Future<ActorSelection>> cohortFutures = Lists.newArrayList();
         for(int i = 1; i <= nCohorts; i++) {
-            cohortPathFutures.add(newCohortPath());
+            cohortFutures.add(newCohort());
         }
 
-        return new ThreePhaseCommitCohortProxy(actorContext, cohortPathFutures, "txn-1");
+        return new ThreePhaseCommitCohortProxy(actorContext, cohortFutures, "txn-1");
     }
 
     private ThreePhaseCommitCohortProxy setupProxyWithFailedCohortPath()
             throws Exception {
-        List<Future<ActorPath>> cohortPathFutures = Lists.newArrayList();
-        cohortPathFutures.add(newCohortPath());
-        cohortPathFutures.add(Futures.<ActorPath>failed(new TestException()));
+        List<Future<ActorSelection>> cohortFutures = Lists.newArrayList();
+        cohortFutures.add(newCohort());
+        cohortFutures.add(Futures.<ActorSelection>failed(new TestException()));
 
-        return new ThreePhaseCommitCohortProxy(actorContext, cohortPathFutures, "txn-1");
+        return new ThreePhaseCommitCohortProxy(actorContext, cohortFutures, "txn-1");
     }
 
     private void setupMockActorContext(Class<?> requestType, Object... responses) {
@@ -91,12 +87,12 @@ public class ThreePhaseCommitCohortProxyTest extends AbstractActorTest {
                     .successful(((SerializableMessage) responses[i]).toSerializable()));
         }
 
-        stubber.when(actorContext).executeRemoteOperationAsync(any(ActorSelection.class),
+        stubber.when(actorContext).executeOperationAsync(any(ActorSelection.class),
                 isA(requestType));
     }
 
     private void verifyCohortInvocations(int nCohorts, Class<?> requestType) {
-        verify(actorContext, times(nCohorts)).executeRemoteOperationAsync(
+        verify(actorContext, times(nCohorts)).executeOperationAsync(
                 any(ActorSelection.class), isA(requestType));
     }
 
@@ -198,24 +194,13 @@ public class ThreePhaseCommitCohortProxyTest extends AbstractActorTest {
 
     @Test
     public void testPreCommit() throws Exception {
+        // Precommit is currently a no-op
         ThreePhaseCommitCohortProxy proxy = setupProxy(1);
 
         setupMockActorContext(PreCommitTransaction.SERIALIZABLE_CLASS,
                 new PreCommitTransactionReply());
 
         proxy.preCommit().get(5, TimeUnit.SECONDS);
-
-        verifyCohortInvocations(1, PreCommitTransaction.SERIALIZABLE_CLASS);
-    }
-
-    @Test(expected = ExecutionException.class)
-    public void testPreCommitWithFailure() throws Exception {
-        ThreePhaseCommitCohortProxy proxy = setupProxy(2);
-
-        setupMockActorContext(PreCommitTransaction.SERIALIZABLE_CLASS,
-                new PreCommitTransactionReply(), new RuntimeException("mock"));
-
-        proxy.preCommit().get(5, TimeUnit.SECONDS);
     }
 
     @Test
@@ -317,7 +302,6 @@ public class ThreePhaseCommitCohortProxyTest extends AbstractActorTest {
         proxy.commit().get(5, TimeUnit.SECONDS);
 
         verifyCohortInvocations(2, CanCommitTransaction.SERIALIZABLE_CLASS);
-        verifyCohortInvocations(2, PreCommitTransaction.SERIALIZABLE_CLASS);
         verifyCohortInvocations(2, CommitTransaction.SERIALIZABLE_CLASS);
     }
 }
index e5392e025158704f44d152306aaa727b64d460e8..f2b849122a3c0fced5f8925b0ab6d7e80080152c 100644 (file)
@@ -1,28 +1,17 @@
 package org.opendaylight.controller.cluster.datastore;
 
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-import akka.actor.ActorPath;
 import akka.actor.ActorRef;
 import akka.actor.ActorSelection;
+import akka.actor.ActorSystem;
 import akka.actor.Props;
 import akka.dispatch.Futures;
-
 import com.google.common.base.Optional;
 import com.google.common.util.concurrent.CheckedFuture;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentMatcher;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-
-import static org.opendaylight.controller.cluster.datastore.TransactionProxy.TransactionType.READ_ONLY;
-import static org.opendaylight.controller.cluster.datastore.TransactionProxy.TransactionType.WRITE_ONLY;
-import static org.opendaylight.controller.cluster.datastore.TransactionProxy.TransactionType.READ_WRITE;
-
 import org.opendaylight.controller.cluster.datastore.TransactionProxy.TransactionType;
 import org.opendaylight.controller.cluster.datastore.exceptions.PrimaryNotFoundException;
 import org.opendaylight.controller.cluster.datastore.exceptions.TimeoutException;
@@ -52,22 +41,27 @@ import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCoh
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-
 import scala.concurrent.Await;
 import scala.concurrent.Future;
 import scala.concurrent.duration.Duration;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
-
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.argThat;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.argThat;
 import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.isA;
 import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.opendaylight.controller.cluster.datastore.TransactionProxy.TransactionType.READ_ONLY;
+import static org.opendaylight.controller.cluster.datastore.TransactionProxy.TransactionType.READ_WRITE;
+import static org.opendaylight.controller.cluster.datastore.TransactionProxy.TransactionType.WRITE_ONLY;
 
 @SuppressWarnings("resource")
 public class TransactionProxyTest extends AbstractActorTest {
@@ -87,6 +81,9 @@ public class TransactionProxyTest extends AbstractActorTest {
 
     private SchemaContext schemaContext;
 
+    @Mock
+    private ClusterWrapper mockClusterWrapper;
+
     String memberName = "mock-member";
 
     @Before
@@ -98,6 +95,7 @@ public class TransactionProxyTest extends AbstractActorTest {
         doReturn(getSystem()).when(mockActorContext).getActorSystem();
         doReturn(memberName).when(mockActorContext).getCurrentMemberName();
         doReturn(schemaContext).when(mockActorContext).getSchemaContext();
+        doReturn(mockClusterWrapper).when(mockActorContext).getClusterWrapper();
 
         ShardStrategyFactory.setConfiguration(configuration);
     }
@@ -116,7 +114,7 @@ public class TransactionProxyTest extends AbstractActorTest {
         return argThat(matcher);
     }
 
-    private DataExists eqDataExists() {
+    private DataExists eqSerializedDataExists() {
         ArgumentMatcher<DataExists> matcher = new ArgumentMatcher<DataExists>() {
             @Override
             public boolean matches(Object argument) {
@@ -128,7 +126,19 @@ public class TransactionProxyTest extends AbstractActorTest {
         return argThat(matcher);
     }
 
-    private ReadData eqReadData() {
+    private DataExists eqDataExists() {
+        ArgumentMatcher<DataExists> matcher = new ArgumentMatcher<DataExists>() {
+            @Override
+            public boolean matches(Object argument) {
+                return (argument instanceof DataExists) &&
+                    ((DataExists)argument).getPath().equals(TestModel.TEST_PATH);
+            }
+        };
+
+        return argThat(matcher);
+    }
+
+    private ReadData eqSerializedReadData() {
         ArgumentMatcher<ReadData> matcher = new ArgumentMatcher<ReadData>() {
             @Override
             public boolean matches(Object argument) {
@@ -140,7 +150,19 @@ public class TransactionProxyTest extends AbstractActorTest {
         return argThat(matcher);
     }
 
-    private WriteData eqWriteData(final NormalizedNode<?, ?> nodeToWrite) {
+    private ReadData eqReadData() {
+        ArgumentMatcher<ReadData> matcher = new ArgumentMatcher<ReadData>() {
+            @Override
+            public boolean matches(Object argument) {
+                return (argument instanceof ReadData) &&
+                    ((ReadData)argument).getPath().equals(TestModel.TEST_PATH);
+            }
+        };
+
+        return argThat(matcher);
+    }
+
+    private WriteData eqSerializedWriteData(final NormalizedNode<?, ?> nodeToWrite) {
         ArgumentMatcher<WriteData> matcher = new ArgumentMatcher<WriteData>() {
             @Override
             public boolean matches(Object argument) {
@@ -157,7 +179,23 @@ public class TransactionProxyTest extends AbstractActorTest {
         return argThat(matcher);
     }
 
-    private MergeData eqMergeData(final NormalizedNode<?, ?> nodeToWrite) {
+    private WriteData eqWriteData(final NormalizedNode<?, ?> nodeToWrite) {
+        ArgumentMatcher<WriteData> matcher = new ArgumentMatcher<WriteData>() {
+            @Override
+            public boolean matches(Object argument) {
+                if(argument instanceof WriteData) {
+                    WriteData obj = (WriteData) argument;
+                    return obj.getPath().equals(TestModel.TEST_PATH) &&
+                        obj.getData().equals(nodeToWrite);
+                }
+                return false;
+            }
+        };
+
+        return argThat(matcher);
+    }
+
+    private MergeData eqSerializedMergeData(final NormalizedNode<?, ?> nodeToWrite) {
         ArgumentMatcher<MergeData> matcher = new ArgumentMatcher<MergeData>() {
             @Override
             public boolean matches(Object argument) {
@@ -174,7 +212,24 @@ public class TransactionProxyTest extends AbstractActorTest {
         return argThat(matcher);
     }
 
-    private DeleteData eqDeleteData() {
+    private MergeData eqMergeData(final NormalizedNode<?, ?> nodeToWrite) {
+        ArgumentMatcher<MergeData> matcher = new ArgumentMatcher<MergeData>() {
+            @Override
+            public boolean matches(Object argument) {
+                if(argument instanceof MergeData) {
+                    MergeData obj = ((MergeData) argument);
+                    return obj.getPath().equals(TestModel.TEST_PATH) &&
+                        obj.getData().equals(nodeToWrite);
+                }
+
+               return false;
+            }
+        };
+
+        return argThat(matcher);
+    }
+
+    private DeleteData eqSerializedDeleteData() {
         ArgumentMatcher<DeleteData> matcher = new ArgumentMatcher<DeleteData>() {
             @Override
             public boolean matches(Object argument) {
@@ -186,30 +241,67 @@ public class TransactionProxyTest extends AbstractActorTest {
         return argThat(matcher);
     }
 
-    private Future<Object> readyTxReply(ActorPath path) {
+        private DeleteData eqDeleteData() {
+        ArgumentMatcher<DeleteData> matcher = new ArgumentMatcher<DeleteData>() {
+            @Override
+            public boolean matches(Object argument) {
+                return argument instanceof DeleteData &&
+                    ((DeleteData)argument).getPath().equals(TestModel.TEST_PATH);
+            }
+        };
+
+        return argThat(matcher);
+    }
+
+    private Future<Object> readySerializedTxReply(String path) {
         return Futures.successful((Object)new ReadyTransactionReply(path).toSerializable());
     }
 
-    private Future<Object> readDataReply(NormalizedNode<?, ?> data) {
+    private Future<Object> readyTxReply(String path) {
+        return Futures.successful((Object)new ReadyTransactionReply(path));
+    }
+
+
+    private Future<Object> readSerializedDataReply(NormalizedNode<?, ?> data) {
         return Futures.successful(new ReadDataReply(schemaContext, data).toSerializable());
     }
 
-    private Future<Object> dataExistsReply(boolean exists) {
+    private Future<ReadDataReply> readDataReply(NormalizedNode<?, ?> data) {
+        return Futures.successful(new ReadDataReply(schemaContext, data));
+    }
+
+    private Future<Object> dataExistsSerializedReply(boolean exists) {
         return Futures.successful(new DataExistsReply(exists).toSerializable());
     }
 
-    private Future<Object> writeDataReply() {
+    private Future<DataExistsReply> dataExistsReply(boolean exists) {
+        return Futures.successful(new DataExistsReply(exists));
+    }
+
+    private Future<Object> writeSerializedDataReply() {
         return Futures.successful(new WriteDataReply().toSerializable());
     }
 
-    private Future<Object> mergeDataReply() {
+    private Future<WriteDataReply> writeDataReply() {
+        return Futures.successful(new WriteDataReply());
+    }
+
+    private Future<Object> mergeSerializedDataReply() {
         return Futures.successful(new MergeDataReply().toSerializable());
     }
 
-    private Future<Object> deleteDataReply() {
+    private Future<MergeDataReply> mergeDataReply() {
+        return Futures.successful(new MergeDataReply());
+    }
+
+    private Future<Object> deleteSerializedDataReply() {
         return Futures.successful(new DeleteDataReply().toSerializable());
     }
 
+    private Future<DeleteDataReply> deleteDataReply() {
+        return Futures.successful(new DeleteDataReply());
+    }
+
     private ActorSelection actorSelection(ActorRef actorRef) {
         return getSystem().actorSelection(actorRef.path());
     }
@@ -220,16 +312,19 @@ public class TransactionProxyTest extends AbstractActorTest {
             .setTransactionId("txn-1").build();
     }
 
-    private ActorRef setupActorContextWithInitialCreateTransaction(TransactionType type) {
-        ActorRef actorRef = getSystem().actorOf(Props.create(DoNothingActor.class));
-        doReturn(getSystem().actorSelection(actorRef.path())).
+    private ActorRef setupActorContextWithInitialCreateTransaction(ActorSystem actorSystem, TransactionType type) {
+        ActorRef actorRef = actorSystem.actorOf(Props.create(DoNothingActor.class));
+        doReturn(actorSystem.actorSelection(actorRef.path())).
                 when(mockActorContext).actorSelection(actorRef.path().toString());
+
+        doReturn(Optional.of(actorSystem.actorSelection(actorRef.path()))).
+                when(mockActorContext).findPrimaryShard(eq(DefaultShardStrategy.DEFAULT_SHARD));
+
         doReturn(createTransactionReply(actorRef)).when(mockActorContext).
-                executeShardOperation(eq(DefaultShardStrategy.DEFAULT_SHARD),
+                executeOperation(eq(actorSystem.actorSelection(actorRef.path())),
                         eqCreateTransaction(memberName, type));
-        doReturn(actorRef.path().toString()).when(mockActorContext).resolvePath(
-                anyString(), eq(actorRef.path().toString()));
-        doReturn(actorRef.path()).when(mockActorContext).actorFor(actorRef.path().toString());
+
+        doReturn(false).when(mockActorContext).isLocalPath(actorRef.path().toString());
 
         return actorRef;
     }
@@ -247,13 +342,13 @@ public class TransactionProxyTest extends AbstractActorTest {
 
     @Test
     public void testRead() throws Exception {
-        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(READ_ONLY);
+        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), READ_ONLY);
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 READ_ONLY);
 
-        doReturn(readDataReply(null)).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqReadData());
+        doReturn(readSerializedDataReply(null)).when(mockActorContext).executeOperationAsync(
+                eq(actorSelection(actorRef)), eqSerializedReadData());
 
         Optional<NormalizedNode<?, ?>> readOptional = transactionProxy.read(
                 TestModel.TEST_PATH).get(5, TimeUnit.SECONDS);
@@ -262,8 +357,8 @@ public class TransactionProxyTest extends AbstractActorTest {
 
         NormalizedNode<?, ?> expectedNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
 
-        doReturn(readDataReply(expectedNode)).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqReadData());
+        doReturn(readSerializedDataReply(expectedNode)).when(mockActorContext).executeOperationAsync(
+                eq(actorSelection(actorRef)), eqSerializedReadData());
 
         readOptional = transactionProxy.read(TestModel.TEST_PATH).get(5, TimeUnit.SECONDS);
 
@@ -274,10 +369,10 @@ public class TransactionProxyTest extends AbstractActorTest {
 
     @Test(expected = ReadFailedException.class)
     public void testReadWithInvalidReplyMessageType() throws Exception {
-        setupActorContextWithInitialCreateTransaction(READ_ONLY);
+        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), READ_ONLY);
 
         doReturn(Futures.successful(new Object())).when(mockActorContext).
-                executeRemoteOperationAsync(any(ActorSelection.class), any());
+                executeOperationAsync(any(ActorSelection.class), any());
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 READ_ONLY);
@@ -287,10 +382,10 @@ public class TransactionProxyTest extends AbstractActorTest {
 
     @Test(expected = TestException.class)
     public void testReadWithAsyncRemoteOperatonFailure() throws Throwable {
-        setupActorContextWithInitialCreateTransaction(READ_ONLY);
+        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), READ_ONLY);
 
         doReturn(Futures.failed(new TestException())).when(mockActorContext).
-                executeRemoteOperationAsync(any(ActorSelection.class), any());
+                executeOperationAsync(any(ActorSelection.class), any());
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 READ_ONLY);
@@ -300,12 +395,17 @@ public class TransactionProxyTest extends AbstractActorTest {
 
     private void testExceptionOnInitialCreateTransaction(Exception exToThrow, Invoker invoker)
             throws Throwable {
+        ActorRef actorRef = getSystem().actorOf(Props.create(DoNothingActor.class));
 
-        doThrow(exToThrow).when(mockActorContext).executeShardOperation(
-                anyString(), any());
+        if (exToThrow instanceof PrimaryNotFoundException) {
+            doReturn(Optional.absent()).when(mockActorContext).findPrimaryShard(anyString());
+        } else {
+            doReturn(Optional.of(getSystem().actorSelection(actorRef.path()))).
+                    when(mockActorContext).findPrimaryShard(anyString());
+        }
+        doThrow(exToThrow).when(mockActorContext).executeOperation(any(ActorSelection.class), any());
 
-        TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
-                READ_ONLY);
+        TransactionProxy transactionProxy = new TransactionProxy(mockActorContext, READ_ONLY);
 
         propagateReadFailedExceptionCause(invoker.invoke(transactionProxy));
     }
@@ -337,18 +437,18 @@ public class TransactionProxyTest extends AbstractActorTest {
 
     @Test(expected = TestException.class)
     public void testReadWithPriorRecordingOperationFailure() throws Throwable {
-        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(READ_WRITE);
+        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), READ_WRITE);
 
         NormalizedNode<?, ?> nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
 
-        doReturn(writeDataReply()).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqWriteData(nodeToWrite));
+        doReturn(writeSerializedDataReply()).when(mockActorContext).executeOperationAsync(
+                eq(actorSelection(actorRef)), eqSerializedWriteData(nodeToWrite));
 
         doReturn(Futures.failed(new TestException())).when(mockActorContext).
-                executeRemoteOperationAsync(eq(actorSelection(actorRef)), eqDeleteData());
+                executeOperationAsync(eq(actorSelection(actorRef)), eqSerializedDeleteData());
 
-        doReturn(readDataReply(null)).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqReadData());
+        doReturn(readSerializedDataReply(null)).when(mockActorContext).executeOperationAsync(
+                eq(actorSelection(actorRef)), eqSerializedReadData());
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 READ_WRITE);
@@ -360,22 +460,22 @@ public class TransactionProxyTest extends AbstractActorTest {
         try {
             propagateReadFailedExceptionCause(transactionProxy.read(TestModel.TEST_PATH));
         } finally {
-            verify(mockActorContext, times(0)).executeRemoteOperationAsync(
-                    eq(actorSelection(actorRef)), eqReadData());
+            verify(mockActorContext, times(0)).executeOperationAsync(
+                    eq(actorSelection(actorRef)), eqSerializedReadData());
         }
     }
 
     @Test
     public void testReadWithPriorRecordingOperationSuccessful() throws Throwable {
-        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(READ_WRITE);
+        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), READ_WRITE);
 
         NormalizedNode<?, ?> expectedNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
 
-        doReturn(writeDataReply()).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqWriteData(expectedNode));
+        doReturn(writeSerializedDataReply()).when(mockActorContext).executeOperationAsync(
+                eq(actorSelection(actorRef)), eqSerializedWriteData(expectedNode));
 
-        doReturn(readDataReply(expectedNode)).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqReadData());
+        doReturn(readSerializedDataReply(expectedNode)).when(mockActorContext).executeOperationAsync(
+                eq(actorSelection(actorRef)), eqSerializedReadData());
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 READ_WRITE);
@@ -401,20 +501,20 @@ public class TransactionProxyTest extends AbstractActorTest {
 
     @Test
     public void testExists() throws Exception {
-        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(READ_ONLY);
+        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), READ_ONLY);
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 READ_ONLY);
 
-        doReturn(dataExistsReply(false)).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqDataExists());
+        doReturn(dataExistsSerializedReply(false)).when(mockActorContext).executeOperationAsync(
+                eq(actorSelection(actorRef)), eqSerializedDataExists());
 
         Boolean exists = transactionProxy.exists(TestModel.TEST_PATH).checkedGet();
 
         assertEquals("Exists response", false, exists);
 
-        doReturn(dataExistsReply(true)).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqDataExists());
+        doReturn(dataExistsSerializedReply(true)).when(mockActorContext).executeOperationAsync(
+                eq(actorSelection(actorRef)), eqSerializedDataExists());
 
         exists = transactionProxy.exists(TestModel.TEST_PATH).checkedGet();
 
@@ -433,10 +533,10 @@ public class TransactionProxyTest extends AbstractActorTest {
 
     @Test(expected = ReadFailedException.class)
     public void testExistsWithInvalidReplyMessageType() throws Exception {
-        setupActorContextWithInitialCreateTransaction(READ_ONLY);
+        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), READ_ONLY);
 
         doReturn(Futures.successful(new Object())).when(mockActorContext).
-                executeRemoteOperationAsync(any(ActorSelection.class), any());
+                executeOperationAsync(any(ActorSelection.class), any());
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 READ_ONLY);
@@ -446,10 +546,10 @@ public class TransactionProxyTest extends AbstractActorTest {
 
     @Test(expected = TestException.class)
     public void testExistsWithAsyncRemoteOperatonFailure() throws Throwable {
-        setupActorContextWithInitialCreateTransaction(READ_ONLY);
+        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), READ_ONLY);
 
         doReturn(Futures.failed(new TestException())).when(mockActorContext).
-                executeRemoteOperationAsync(any(ActorSelection.class), any());
+                executeOperationAsync(any(ActorSelection.class), any());
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 READ_ONLY);
@@ -459,18 +559,18 @@ public class TransactionProxyTest extends AbstractActorTest {
 
     @Test(expected = TestException.class)
     public void testExistsWithPriorRecordingOperationFailure() throws Throwable {
-        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(READ_WRITE);
+        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), READ_WRITE);
 
         NormalizedNode<?, ?> nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
 
-        doReturn(writeDataReply()).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqWriteData(nodeToWrite));
+        doReturn(writeSerializedDataReply()).when(mockActorContext).executeOperationAsync(
+                eq(actorSelection(actorRef)), eqSerializedWriteData(nodeToWrite));
 
         doReturn(Futures.failed(new TestException())).when(mockActorContext).
-                executeRemoteOperationAsync(eq(actorSelection(actorRef)), eqDeleteData());
+                executeOperationAsync(eq(actorSelection(actorRef)), eqSerializedDeleteData());
 
-        doReturn(dataExistsReply(false)).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqDataExists());
+        doReturn(dataExistsSerializedReply(false)).when(mockActorContext).executeOperationAsync(
+                eq(actorSelection(actorRef)), eqSerializedDataExists());
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 READ_WRITE);
@@ -482,22 +582,22 @@ public class TransactionProxyTest extends AbstractActorTest {
         try {
             propagateReadFailedExceptionCause(transactionProxy.exists(TestModel.TEST_PATH));
         } finally {
-            verify(mockActorContext, times(0)).executeRemoteOperationAsync(
-                    eq(actorSelection(actorRef)), eqDataExists());
+            verify(mockActorContext, times(0)).executeOperationAsync(
+                    eq(actorSelection(actorRef)), eqSerializedDataExists());
         }
     }
 
     @Test
     public void testExistsWithPriorRecordingOperationSuccessful() throws Throwable {
-        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(READ_WRITE);
+        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), READ_WRITE);
 
         NormalizedNode<?, ?> nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
 
-        doReturn(writeDataReply()).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqWriteData(nodeToWrite));
+        doReturn(writeSerializedDataReply()).when(mockActorContext).executeOperationAsync(
+                eq(actorSelection(actorRef)), eqSerializedWriteData(nodeToWrite));
 
-        doReturn(dataExistsReply(true)).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqDataExists());
+        doReturn(dataExistsSerializedReply(true)).when(mockActorContext).executeOperationAsync(
+                eq(actorSelection(actorRef)), eqSerializedDataExists());
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 READ_WRITE);
@@ -543,20 +643,20 @@ public class TransactionProxyTest extends AbstractActorTest {
 
     @Test
     public void testWrite() throws Exception {
-        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(WRITE_ONLY);
+        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), WRITE_ONLY);
 
         NormalizedNode<?, ?> nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
 
-        doReturn(writeDataReply()).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqWriteData(nodeToWrite));
+        doReturn(writeSerializedDataReply()).when(mockActorContext).executeOperationAsync(
+                eq(actorSelection(actorRef)), eqSerializedWriteData(nodeToWrite));
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 WRITE_ONLY);
 
         transactionProxy.write(TestModel.TEST_PATH, nodeToWrite);
 
-        verify(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqWriteData(nodeToWrite));
+        verify(mockActorContext).executeOperationAsync(
+                eq(actorSelection(actorRef)), eqSerializedWriteData(nodeToWrite));
 
         verifyRecordingOperationFutures(transactionProxy.getRecordedOperationFutures(),
                 WriteDataReply.SERIALIZABLE_CLASS);
@@ -586,20 +686,20 @@ public class TransactionProxyTest extends AbstractActorTest {
 
     @Test
     public void testMerge() throws Exception {
-        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(WRITE_ONLY);
+        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), WRITE_ONLY);
 
         NormalizedNode<?, ?> nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
 
-        doReturn(mergeDataReply()).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqMergeData(nodeToWrite));
+        doReturn(mergeSerializedDataReply()).when(mockActorContext).executeOperationAsync(
+                eq(actorSelection(actorRef)), eqSerializedMergeData(nodeToWrite));
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 WRITE_ONLY);
 
         transactionProxy.merge(TestModel.TEST_PATH, nodeToWrite);
 
-        verify(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqMergeData(nodeToWrite));
+        verify(mockActorContext).executeOperationAsync(
+                eq(actorSelection(actorRef)), eqSerializedMergeData(nodeToWrite));
 
         verifyRecordingOperationFutures(transactionProxy.getRecordedOperationFutures(),
                 MergeDataReply.SERIALIZABLE_CLASS);
@@ -607,35 +707,35 @@ public class TransactionProxyTest extends AbstractActorTest {
 
     @Test
     public void testDelete() throws Exception {
-        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(WRITE_ONLY);
+        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), WRITE_ONLY);
 
-        doReturn(deleteDataReply()).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqDeleteData());
+        doReturn(deleteSerializedDataReply()).when(mockActorContext).executeOperationAsync(
+                eq(actorSelection(actorRef)), eqSerializedDeleteData());
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 WRITE_ONLY);
 
         transactionProxy.delete(TestModel.TEST_PATH);
 
-        verify(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqDeleteData());
+        verify(mockActorContext).executeOperationAsync(
+                eq(actorSelection(actorRef)), eqSerializedDeleteData());
 
         verifyRecordingOperationFutures(transactionProxy.getRecordedOperationFutures(),
                 DeleteDataReply.SERIALIZABLE_CLASS);
     }
 
-    private void verifyCohortPathFutures(ThreePhaseCommitCohortProxy proxy,
-            Object... expReplies) throws Exception {
+    private void verifyCohortFutures(ThreePhaseCommitCohortProxy proxy,
+        Object... expReplies) throws Exception {
         assertEquals("getReadyOperationFutures size", expReplies.length,
-                proxy.getCohortPathFutures().size());
+                proxy.getCohortFutures().size());
 
         int i = 0;
-        for( Future<ActorPath> future: proxy.getCohortPathFutures()) {
+        for( Future<ActorSelection> future: proxy.getCohortFutures()) {
             assertNotNull("Ready operation Future is null", future);
 
             Object expReply = expReplies[i++];
-            if(expReply instanceof ActorPath) {
-                ActorPath actual = Await.result(future, Duration.create(5, TimeUnit.SECONDS));
+            if(expReply instanceof ActorSelection) {
+                ActorSelection actual = Await.result(future, Duration.create(5, TimeUnit.SECONDS));
                 assertEquals("Cohort actor path", expReply, actual);
             } else {
                 // Expecting exception.
@@ -652,17 +752,17 @@ public class TransactionProxyTest extends AbstractActorTest {
     @SuppressWarnings("unchecked")
     @Test
     public void testReady() throws Exception {
-        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(READ_WRITE);
+        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), READ_WRITE);
 
         NormalizedNode<?, ?> nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
 
-        doReturn(readDataReply(null)).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqReadData());
+        doReturn(readSerializedDataReply(null)).when(mockActorContext).executeOperationAsync(
+                eq(actorSelection(actorRef)), eqSerializedReadData());
 
-        doReturn(writeDataReply()).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqWriteData(nodeToWrite));
+        doReturn(writeSerializedDataReply()).when(mockActorContext).executeOperationAsync(
+                eq(actorSelection(actorRef)), eqSerializedWriteData(nodeToWrite));
 
-        doReturn(readyTxReply(actorRef.path())).when(mockActorContext).executeRemoteOperationAsync(
+        doReturn(readySerializedTxReply(actorRef.path().toString())).when(mockActorContext).executeOperationAsync(
                 eq(actorSelection(actorRef)), isA(ReadyTransaction.SERIALIZABLE_CLASS));
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
@@ -681,25 +781,27 @@ public class TransactionProxyTest extends AbstractActorTest {
         verifyRecordingOperationFutures(transactionProxy.getRecordedOperationFutures(),
                 WriteDataReply.SERIALIZABLE_CLASS);
 
-        verifyCohortPathFutures(proxy, actorRef.path());
+        verifyCohortFutures(proxy, getSystem().actorSelection(actorRef.path()));
     }
 
     @SuppressWarnings("unchecked")
     @Test
     public void testReadyWithRecordingOperationFailure() throws Exception {
-        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(WRITE_ONLY);
+        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), WRITE_ONLY);
 
         NormalizedNode<?, ?> nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
 
-        doReturn(mergeDataReply()).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqMergeData(nodeToWrite));
+        doReturn(mergeSerializedDataReply()).when(mockActorContext).executeOperationAsync(
+                eq(actorSelection(actorRef)), eqSerializedMergeData(nodeToWrite));
 
         doReturn(Futures.failed(new TestException())).when(mockActorContext).
-                executeRemoteOperationAsync(eq(actorSelection(actorRef)), eqWriteData(nodeToWrite));
+                executeOperationAsync(eq(actorSelection(actorRef)), eqSerializedWriteData(nodeToWrite));
 
-        doReturn(readyTxReply(actorRef.path())).when(mockActorContext).executeRemoteOperationAsync(
+        doReturn(readySerializedTxReply(actorRef.path().toString())).when(mockActorContext).executeOperationAsync(
                 eq(actorSelection(actorRef)), isA(ReadyTransaction.SERIALIZABLE_CLASS));
 
+        doReturn(false).when(mockActorContext).isLocalPath(actorRef.path().toString());
+
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 WRITE_ONLY);
 
@@ -716,21 +818,21 @@ public class TransactionProxyTest extends AbstractActorTest {
         verifyRecordingOperationFutures(transactionProxy.getRecordedOperationFutures(),
                 MergeDataReply.SERIALIZABLE_CLASS, TestException.class);
 
-        verifyCohortPathFutures(proxy, TestException.class);
+        verifyCohortFutures(proxy, TestException.class);
     }
 
     @SuppressWarnings("unchecked")
     @Test
     public void testReadyWithReplyFailure() throws Exception {
-        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(WRITE_ONLY);
+        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), WRITE_ONLY);
 
         NormalizedNode<?, ?> nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
 
-        doReturn(mergeDataReply()).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqMergeData(nodeToWrite));
+        doReturn(mergeSerializedDataReply()).when(mockActorContext).executeOperationAsync(
+                eq(actorSelection(actorRef)), eqSerializedMergeData(nodeToWrite));
 
         doReturn(Futures.failed(new TestException())).when(mockActorContext).
-                executeRemoteOperationAsync(eq(actorSelection(actorRef)),
+                executeOperationAsync(eq(actorSelection(actorRef)),
                         isA(ReadyTransaction.SERIALIZABLE_CLASS));
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
@@ -747,14 +849,15 @@ public class TransactionProxyTest extends AbstractActorTest {
         verifyRecordingOperationFutures(transactionProxy.getRecordedOperationFutures(),
                 MergeDataReply.SERIALIZABLE_CLASS);
 
-        verifyCohortPathFutures(proxy, TestException.class);
+        verifyCohortFutures(proxy, TestException.class);
     }
 
     @Test
     public void testReadyWithInitialCreateTransactionFailure() throws Exception {
 
-        doThrow(new PrimaryNotFoundException("mock")).when(mockActorContext).executeShardOperation(
-                anyString(), any());
+        doReturn(Optional.absent()).when(mockActorContext).findPrimaryShard(anyString());
+//        doThrow(new PrimaryNotFoundException("mock")).when(mockActorContext).executeShardOperation(
+//                anyString(), any());
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 WRITE_ONLY);
@@ -773,21 +876,21 @@ public class TransactionProxyTest extends AbstractActorTest {
 
         ThreePhaseCommitCohortProxy proxy = (ThreePhaseCommitCohortProxy) ready;
 
-        verifyCohortPathFutures(proxy, PrimaryNotFoundException.class);
+        verifyCohortFutures(proxy, PrimaryNotFoundException.class);
     }
 
     @SuppressWarnings("unchecked")
     @Test
     public void testReadyWithInvalidReplyMessageType() throws Exception {
-        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(WRITE_ONLY);
+        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), WRITE_ONLY);
 
         NormalizedNode<?, ?> nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
 
-        doReturn(writeDataReply()).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqWriteData(nodeToWrite));
+        doReturn(writeSerializedDataReply()).when(mockActorContext).executeOperationAsync(
+                eq(actorSelection(actorRef)), eqSerializedWriteData(nodeToWrite));
 
         doReturn(Futures.successful(new Object())).when(mockActorContext).
-                executeRemoteOperationAsync(eq(actorSelection(actorRef)),
+                executeOperationAsync(eq(actorSelection(actorRef)),
                         isA(ReadyTransaction.SERIALIZABLE_CLASS));
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
@@ -801,12 +904,12 @@ public class TransactionProxyTest extends AbstractActorTest {
 
         ThreePhaseCommitCohortProxy proxy = (ThreePhaseCommitCohortProxy) ready;
 
-        verifyCohortPathFutures(proxy, IllegalArgumentException.class);
+        verifyCohortFutures(proxy, IllegalArgumentException.class);
     }
 
     @Test
     public void testGetIdentifier() {
-        setupActorContextWithInitialCreateTransaction(READ_ONLY);
+        setupActorContextWithInitialCreateTransaction(getSystem(), READ_ONLY);
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 TransactionProxy.TransactionType.READ_ONLY);
 
@@ -818,10 +921,10 @@ public class TransactionProxyTest extends AbstractActorTest {
     @SuppressWarnings("unchecked")
     @Test
     public void testClose() throws Exception{
-        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(READ_WRITE);
+        ActorRef actorRef = setupActorContextWithInitialCreateTransaction(getSystem(), READ_WRITE);
 
-        doReturn(readDataReply(null)).when(mockActorContext).executeRemoteOperationAsync(
-                eq(actorSelection(actorRef)), eqReadData());
+        doReturn(readSerializedDataReply(null)).when(mockActorContext).executeOperationAsync(
+                eq(actorSelection(actorRef)), eqSerializedReadData());
 
         TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,
                 READ_WRITE);
@@ -830,7 +933,143 @@ public class TransactionProxyTest extends AbstractActorTest {
 
         transactionProxy.close();
 
-        verify(mockActorContext).sendRemoteOperationAsync(
+        verify(mockActorContext).sendOperationAsync(
                 eq(actorSelection(actorRef)), isA(CloseTransaction.SERIALIZABLE_CLASS));
     }
+
+
+    /**
+     * Method to test a local Tx actor. The Tx paths are matched to decide if the
+     * Tx actor is local or not. This is done by mocking the Tx actor path
+     * and the caller paths and ensuring that the paths have the remote-address format
+     *
+     * Note: Since the default akka provider for test is not a RemoteActorRefProvider,
+     * the paths returned for the actors for all the tests are not qualified remote paths.
+     * Hence are treated as non-local/remote actors. In short, all tests except
+     * few below run for remote actors
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testLocalTxActorRead() throws Exception {
+        ActorSystem actorSystem = getSystem();
+        ActorRef shardActorRef = actorSystem.actorOf(Props.create(DoNothingActor.class));
+
+        doReturn(actorSystem.actorSelection(shardActorRef.path())).
+            when(mockActorContext).actorSelection(shardActorRef.path().toString());
+
+        doReturn(Optional.of(actorSystem.actorSelection(shardActorRef.path()))).
+            when(mockActorContext).findPrimaryShard(eq(DefaultShardStrategy.DEFAULT_SHARD));
+
+        String actorPath = "akka.tcp://system@127.0.0.1:2550/user/tx-actor";
+        CreateTransactionReply createTransactionReply = CreateTransactionReply.newBuilder()
+            .setTransactionId("txn-1")
+            .setTransactionActorPath(actorPath)
+            .build();
+
+        doReturn(createTransactionReply).when(mockActorContext).
+            executeOperation(eq(actorSystem.actorSelection(shardActorRef.path())),
+                eqCreateTransaction(memberName, READ_ONLY));
+
+        doReturn(true).when(mockActorContext).isLocalPath(actorPath);
+
+        TransactionProxy transactionProxy = new TransactionProxy(mockActorContext,READ_ONLY);
+
+        // negative test case with null as the reply
+        doReturn(readDataReply(null)).when(mockActorContext).executeOperationAsync(
+            any(ActorSelection.class), eqReadData());
+
+        Optional<NormalizedNode<?, ?>> readOptional = transactionProxy.read(
+            TestModel.TEST_PATH).get(5, TimeUnit.SECONDS);
+
+        assertEquals("NormalizedNode isPresent", false, readOptional.isPresent());
+
+        // test case with node as read data reply
+        NormalizedNode<?, ?> expectedNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
+
+        doReturn(readDataReply(expectedNode)).when(mockActorContext).executeOperationAsync(
+            any(ActorSelection.class), eqReadData());
+
+        readOptional = transactionProxy.read(TestModel.TEST_PATH).get(5, TimeUnit.SECONDS);
+
+        assertEquals("NormalizedNode isPresent", true, readOptional.isPresent());
+
+        assertEquals("Response NormalizedNode", expectedNode, readOptional.get());
+
+        // test for local data exists
+        doReturn(dataExistsReply(true)).when(mockActorContext).executeOperationAsync(
+            any(ActorSelection.class), eqDataExists());
+
+        boolean exists = transactionProxy.exists(TestModel.TEST_PATH).checkedGet();
+
+        assertEquals("Exists response", true, exists);
+    }
+
+    @Test
+    public void testLocalTxActorWrite() throws Exception {
+        ActorSystem actorSystem = getSystem();
+        ActorRef shardActorRef = actorSystem.actorOf(Props.create(DoNothingActor.class));
+
+        doReturn(actorSystem.actorSelection(shardActorRef.path())).
+            when(mockActorContext).actorSelection(shardActorRef.path().toString());
+
+        doReturn(Optional.of(actorSystem.actorSelection(shardActorRef.path()))).
+            when(mockActorContext).findPrimaryShard(eq(DefaultShardStrategy.DEFAULT_SHARD));
+
+        String actorPath = "akka.tcp://system@127.0.0.1:2550/user/tx-actor";
+        CreateTransactionReply createTransactionReply = CreateTransactionReply.newBuilder()
+            .setTransactionId("txn-1")
+            .setTransactionActorPath(actorPath)
+            .build();
+
+        doReturn(createTransactionReply).when(mockActorContext).
+            executeOperation(eq(actorSystem.actorSelection(shardActorRef.path())),
+                eqCreateTransaction(memberName, WRITE_ONLY));
+
+        doReturn(true).when(mockActorContext).isLocalPath(actorPath);
+
+        NormalizedNode<?, ?> nodeToWrite = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
+
+        doReturn(writeDataReply()).when(mockActorContext).executeOperationAsync(
+            any(ActorSelection.class), eqWriteData(nodeToWrite));
+
+        TransactionProxy transactionProxy = new TransactionProxy(mockActorContext, WRITE_ONLY);
+        transactionProxy.write(TestModel.TEST_PATH, nodeToWrite);
+
+        verify(mockActorContext).executeOperationAsync(
+            any(ActorSelection.class), eqWriteData(nodeToWrite));
+
+        //testing local merge
+        doReturn(mergeDataReply()).when(mockActorContext).executeOperationAsync(
+            any(ActorSelection.class), eqMergeData(nodeToWrite));
+
+        transactionProxy.merge(TestModel.TEST_PATH, nodeToWrite);
+
+        verify(mockActorContext).executeOperationAsync(
+            any(ActorSelection.class), eqMergeData(nodeToWrite));
+
+
+        //testing local delete
+        doReturn(deleteDataReply()).when(mockActorContext).executeOperationAsync(
+            any(ActorSelection.class), eqDeleteData());
+
+        transactionProxy.delete(TestModel.TEST_PATH);
+
+        verify(mockActorContext).executeOperationAsync(any(ActorSelection.class), eqDeleteData());
+
+        verifyRecordingOperationFutures(transactionProxy.getRecordedOperationFutures(),
+            WriteDataReply.class, MergeDataReply.class, DeleteDataReply.class);
+
+        // testing ready
+        doReturn(readyTxReply(shardActorRef.path().toString())).when(mockActorContext).executeOperationAsync(
+            any(ActorSelection.class), isA(ReadyTransaction.class));
+
+        DOMStoreThreePhaseCommitCohort ready = transactionProxy.ready();
+
+        assertTrue(ready instanceof ThreePhaseCommitCohortProxy);
+
+        ThreePhaseCommitCohortProxy proxy = (ThreePhaseCommitCohortProxy) ready;
+
+        verifyCohortFutures(proxy, getSystem().actorSelection(shardActorRef.path()));
+    }
 }
index afcd045434450d4dee2e89a8efb13b7866e77320..0b5e7132c77791cab3e2c4276fe1fb966bb6445e 100644 (file)
@@ -14,5 +14,14 @@ public class ShardIdentifierTest {
         assertEquals("member-1-shard-inventory-config", id.toString());
     }
 
+    @Test
+    public void testFromShardIdString(){
+        String shardIdStr = "member-1-shard-inventory-config";
+
+        ShardIdentifier id = ShardIdentifier.builder().fromShardIdString(shardIdStr).build();
 
+        assertEquals("member-1", id.getMemberName());
+        assertEquals("inventory", id.getShardName());
+        assertEquals("config", id.getType());
+    }
 }
index 5d8fb8393d6c4fd773a0a94b6fd156ac02fe1c14..60f9a2d9dc4d9e2660137eaa77c7df491d124361 100644 (file)
@@ -1,14 +1,12 @@
 package org.opendaylight.controller.cluster.datastore.utils;
 
-import java.util.concurrent.TimeUnit;
 import akka.actor.ActorRef;
 import akka.actor.ActorSelection;
-import akka.actor.ActorSystem;
 import akka.actor.Props;
 import akka.actor.UntypedActor;
 import akka.japi.Creator;
 import akka.testkit.JavaTestKit;
-
+import com.google.common.base.Optional;
 import org.junit.Test;
 import org.opendaylight.controller.cluster.datastore.AbstractActorTest;
 import org.opendaylight.controller.cluster.datastore.ClusterWrapper;
@@ -16,49 +14,15 @@ import org.opendaylight.controller.cluster.datastore.Configuration;
 import org.opendaylight.controller.cluster.datastore.messages.FindLocalShard;
 import org.opendaylight.controller.cluster.datastore.messages.LocalShardFound;
 import org.opendaylight.controller.cluster.datastore.messages.LocalShardNotFound;
-
 import scala.concurrent.Await;
 import scala.concurrent.Future;
 import scala.concurrent.duration.Duration;
+import java.util.concurrent.TimeUnit;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 
 public class ActorContextTest extends AbstractActorTest{
-    @Test
-    public void testResolvePathForRemoteActor(){
-        ActorContext actorContext =
-            new ActorContext(mock(ActorSystem.class), mock(ActorRef.class),mock(
-                ClusterWrapper.class),
-                mock(Configuration.class));
-
-        String actual = actorContext.resolvePath(
-            "akka.tcp://system@127.0.0.1:2550/user/shardmanager/shard",
-            "akka://system/user/shardmanager/shard/transaction");
-
-        String expected = "akka.tcp://system@127.0.0.1:2550/user/shardmanager/shard/transaction";
-
-        assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testResolvePathForLocalActor(){
-        ActorContext actorContext =
-            new ActorContext(getSystem(), mock(ActorRef.class), mock(ClusterWrapper.class),
-                mock(Configuration.class));
-
-        String actual = actorContext.resolvePath(
-            "akka://system/user/shardmanager/shard",
-            "akka://system/user/shardmanager/shard/transaction");
-
-        String expected = "akka://system/user/shardmanager/shard/transaction";
-
-        assertEquals(expected, actual);
-
-        System.out.println(actorContext
-            .actorFor("akka://system/user/shardmanager/shard/transaction"));
-    }
-
 
     private static class MockShardManager extends UntypedActor {
 
@@ -101,7 +65,7 @@ public class ActorContextTest extends AbstractActorTest{
     }
 
     @Test
-    public void testExecuteLocalShardOperationWithShardFound(){
+    public void testFindLocalShardWithShardFound(){
         new JavaTestKit(getSystem()) {{
 
             new Within(duration("1 seconds")) {
@@ -117,9 +81,9 @@ public class ActorContextTest extends AbstractActorTest{
                         new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class),
                             mock(Configuration.class));
 
-                    Object out = actorContext.executeLocalShardOperation("default", "hello");
+                    Optional<ActorRef> out = actorContext.findLocalShard("default");
 
-                    assertEquals("hello", out);
+                    assertEquals(shardActorRef, out.get());
 
 
                     expectNoMsg();
@@ -130,149 +94,92 @@ public class ActorContextTest extends AbstractActorTest{
     }
 
     @Test
-    public void testExecuteLocalShardOperationWithShardNotFound(){
+    public void testFindLocalShardWithShardNotFound(){
         new JavaTestKit(getSystem()) {{
+            ActorRef shardManagerActorRef = getSystem()
+                    .actorOf(MockShardManager.props(false, null));
 
-            new Within(duration("1 seconds")) {
-                @Override
-                protected void run() {
-
-                    ActorRef shardManagerActorRef = getSystem()
-                        .actorOf(MockShardManager.props(false, null));
-
-                    ActorContext actorContext =
-                        new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class),
+            ActorContext actorContext =
+                    new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class),
                             mock(Configuration.class));
 
-                    Object out = actorContext.executeLocalShardOperation("default", "hello");
-
-                    assertNull(out);
-
-
-                    expectNoMsg();
-                }
-            };
+            Optional<ActorRef> out = actorContext.findLocalShard("default");
+            assertTrue(!out.isPresent());
         }};
 
     }
 
-
     @Test
-    public void testFindLocalShardWithShardFound(){
-        new JavaTestKit(getSystem()) {{
-
-            new Within(duration("1 seconds")) {
-                @Override
-                protected void run() {
-
-                    ActorRef shardActorRef = getSystem().actorOf(Props.create(EchoActor.class));
-
-                    ActorRef shardManagerActorRef = getSystem()
-                        .actorOf(MockShardManager.props(true, shardActorRef));
-
-                    ActorContext actorContext =
-                        new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class),
-                            mock(Configuration.class));
-
-                    Object out = actorContext.findLocalShard("default");
-
-                    assertEquals(shardActorRef, out);
-
-
-                    expectNoMsg();
-                }
-            };
-        }};
-
-    }
-
-    @Test
-    public void testFindLocalShardWithShardNotFound(){
+    public void testExecuteRemoteOperation() {
         new JavaTestKit(getSystem()) {{
+            ActorRef shardActorRef = getSystem().actorOf(Props.create(EchoActor.class));
 
-            new Within(duration("1 seconds")) {
-                @Override
-                protected void run() {
+            ActorRef shardManagerActorRef = getSystem()
+                    .actorOf(MockShardManager.props(true, shardActorRef));
 
-                    ActorRef shardManagerActorRef = getSystem()
-                        .actorOf(MockShardManager.props(false, null));
-
-                    ActorContext actorContext =
-                        new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class),
+            ActorContext actorContext =
+                    new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class),
                             mock(Configuration.class));
 
-                    Object out = actorContext.findLocalShard("default");
-
-                    assertNull(out);
+            ActorSelection actor = actorContext.actorSelection(shardActorRef.path());
 
+            Object out = actorContext.executeOperation(actor, "hello");
 
-                    expectNoMsg();
-                }
-            };
+            assertEquals("hello", out);
         }};
-
     }
 
     @Test
-    public void testExecuteRemoteOperation() {
+    public void testExecuteRemoteOperationAsync() {
         new JavaTestKit(getSystem()) {{
+            ActorRef shardActorRef = getSystem().actorOf(Props.create(EchoActor.class));
 
-            new Within(duration("3 seconds")) {
-                @Override
-                protected void run() {
-
-                    ActorRef shardActorRef = getSystem().actorOf(Props.create(EchoActor.class));
-
-                    ActorRef shardManagerActorRef = getSystem()
-                        .actorOf(MockShardManager.props(true, shardActorRef));
+            ActorRef shardManagerActorRef = getSystem()
+                    .actorOf(MockShardManager.props(true, shardActorRef));
 
-                    ActorContext actorContext =
-                        new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class),
+            ActorContext actorContext =
+                    new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class),
                             mock(Configuration.class));
 
-                    ActorSelection actor = actorContext.actorSelection(shardActorRef.path());
-
-                    Object out = actorContext.executeRemoteOperation(actor, "hello");
+            ActorSelection actor = actorContext.actorSelection(shardActorRef.path());
 
-                    assertEquals("hello", out);
+            Future<Object> future = actorContext.executeOperationAsync(actor, "hello");
 
-                    expectNoMsg();
-                }
-            };
+            try {
+                Object result = Await.result(future, Duration.create(3, TimeUnit.SECONDS));
+                assertEquals("Result", "hello", result);
+            } catch(Exception e) {
+                throw new AssertionError(e);
+            }
         }};
     }
 
     @Test
-    public void testExecuteRemoteOperationAsync() {
-        new JavaTestKit(getSystem()) {{
-
-            new Within(duration("3 seconds")) {
-                @Override
-                protected void run() {
+    public void testIsLocalPath() {
+        MockClusterWrapper clusterWrapper = new MockClusterWrapper();
+        ActorContext actorContext =
+                new ActorContext(getSystem(), null, clusterWrapper, mock(Configuration.class));
 
-                    ActorRef shardActorRef = getSystem().actorOf(Props.create(EchoActor.class));
+        clusterWrapper.setSelfAddress("");
+        assertEquals(false, actorContext.isLocalPath(null));
+        assertEquals(false, actorContext.isLocalPath(""));
 
-                    ActorRef shardManagerActorRef = getSystem()
-                        .actorOf(MockShardManager.props(true, shardActorRef));
+        clusterWrapper.setSelfAddress(null);
+        assertEquals(false, actorContext.isLocalPath(""));
 
-                    ActorContext actorContext =
-                        new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class),
-                            mock(Configuration.class));
+        clusterWrapper.setSelfAddress("akka://test/user/$b");
+        assertEquals(false, actorContext.isLocalPath("akka://test/user/$a"));
 
-                    ActorSelection actor = actorContext.actorSelection(shardActorRef.path());
+        clusterWrapper.setSelfAddress("akka.tcp://system@127.0.0.1:2550/");
+        assertEquals(true, actorContext.isLocalPath("akka.tcp://system@127.0.0.1:2550/"));
 
-                    Future<Object> future = actorContext.executeRemoteOperationAsync(actor, "hello");
+        clusterWrapper.setSelfAddress("akka.tcp://system@127.0.0.1:2550");
+        assertEquals(false, actorContext.isLocalPath("akka.tcp://system@127.0.0.1:2550/"));
 
-                    try {
-                        Object result = Await.result(future, Duration.create(3, TimeUnit.SECONDS));
-                        assertEquals("Result", "hello", result);
-                    } catch(Exception e) {
-                        throw new AssertionError(e);
-                    }
+        clusterWrapper.setSelfAddress("akka.tcp://system@128.0.0.1:2550/");
+        assertEquals(false, actorContext.isLocalPath("akka.tcp://system@127.0.0.1:2550/"));
 
-                    expectNoMsg();
-                }
-            };
-        }};
+        clusterWrapper.setSelfAddress("akka.tcp://system@127.0.0.1:2551/");
+        assertEquals(false, actorContext.isLocalPath("akka.tcp://system@127.0.0.1:2550/"));
     }
 }
index c9a0eaf0337929408ec4a16d7c6479a4cf329f69..34867530821d70d4ce7085859a3f79e59a6d9a03 100644 (file)
@@ -7,10 +7,16 @@
  */
 package org.opendaylight.controller.cluster.datastore.utils;
 
+import static org.junit.Assert.assertEquals;
+import java.util.Collections;
+import java.util.Iterator;
 import java.util.Map;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 import com.google.common.collect.Maps;
+import com.google.common.util.concurrent.Uninterruptibles;
 import scala.concurrent.Future;
 import akka.dispatch.Futures;
 import akka.japi.Procedure;
@@ -22,7 +28,9 @@ import akka.persistence.journal.japi.AsyncWriteJournal;
 
 public class InMemoryJournal extends AsyncWriteJournal {
 
-    private static Map<String, Map<Long, Object>> journals = new ConcurrentHashMap<>();
+    private static final Map<String, Map<Long, Object>> journals = new ConcurrentHashMap<>();
+
+    private static final Map<String, CountDownLatch> deleteMessagesCompleteLatches = new ConcurrentHashMap<>();
 
     public static void addEntry(String persistenceId, long sequenceNr, Object data) {
         Map<Long, Object> journal = journals.get(persistenceId);
@@ -31,13 +39,29 @@ public class InMemoryJournal extends AsyncWriteJournal {
             journals.put(persistenceId, journal);
         }
 
-        journal.put(sequenceNr, data);
+        synchronized (journal) {
+            journal.put(sequenceNr, data);
+        }
     }
 
     public static void clear() {
         journals.clear();
     }
 
+    public static Map<Long, Object> get(String persistenceId) {
+        Map<Long, Object> journal = journals.get(persistenceId);
+        return journal != null ? journal : Collections.<Long, Object>emptyMap();
+    }
+
+    public static void waitForDeleteMessagesComplete(String persistenceId) {
+        assertEquals("Recovery complete", true, Uninterruptibles.awaitUninterruptibly(
+                deleteMessagesCompleteLatches.get(persistenceId), 5, TimeUnit.SECONDS));
+    }
+
+    public static void addDeleteMessagesCompleteLatch(String persistenceId) {
+        deleteMessagesCompleteLatches.put(persistenceId, new CountDownLatch(1));
+    }
+
     @Override
     public Future<Void> doAsyncReplayMessages(final String persistenceId, long fromSequenceNr,
             long toSequenceNr, long max, final Procedure<PersistentRepr> replayCallback) {
@@ -49,10 +73,13 @@ public class InMemoryJournal extends AsyncWriteJournal {
                     return null;
                 }
 
-                for (Map.Entry<Long,Object> entry : journal.entrySet()) {
-                    PersistentRepr persistentMessage =
-                        new PersistentImpl(entry.getValue(), entry.getKey(), persistenceId, false, null, null);
-                    replayCallback.apply(persistentMessage);
+                synchronized (journal) {
+                    for (Map.Entry<Long,Object> entry : journal.entrySet()) {
+                        PersistentRepr persistentMessage =
+                                new PersistentImpl(entry.getValue(), entry.getKey(), persistenceId,
+                                        false, null, null);
+                        replayCallback.apply(persistentMessage);
+                    }
                 }
 
                 return null;
@@ -62,12 +89,28 @@ public class InMemoryJournal extends AsyncWriteJournal {
 
     @Override
     public Future<Long> doAsyncReadHighestSequenceNr(String persistenceId, long fromSequenceNr) {
-        return Futures.successful(new Long(0));
+        return Futures.successful(-1L);
     }
 
     @Override
-    public Future<Void> doAsyncWriteMessages(Iterable<PersistentRepr> messages) {
-        return Futures.successful(null);
+    public Future<Void> doAsyncWriteMessages(final Iterable<PersistentRepr> messages) {
+        return Futures.future(new Callable<Void>() {
+            @Override
+            public Void call() throws Exception {
+                for (PersistentRepr repr : messages) {
+                    Map<Long, Object> journal = journals.get(repr.persistenceId());
+                    if(journal == null) {
+                        journal = Maps.newLinkedHashMap();
+                        journals.put(repr.persistenceId(), journal);
+                    }
+
+                    synchronized (journal) {
+                        journal.put(repr.sequenceNr(), repr.payload());
+                    }
+                }
+                return null;
+            }
+        }, context().dispatcher());
     }
 
     @Override
@@ -82,6 +125,24 @@ public class InMemoryJournal extends AsyncWriteJournal {
 
     @Override
     public Future<Void> doAsyncDeleteMessagesTo(String persistenceId, long toSequenceNr, boolean permanent) {
+        Map<Long, Object> journal = journals.get(persistenceId);
+        if(journal != null) {
+            synchronized (journal) {
+                Iterator<Long> iter = journal.keySet().iterator();
+                while(iter.hasNext()) {
+                    Long n = iter.next();
+                    if(n <= toSequenceNr) {
+                        iter.remove();
+                    }
+                }
+            }
+        }
+
+        CountDownLatch latch = deleteMessagesCompleteLatches.get(persistenceId);
+        if(latch != null) {
+            latch.countDown();
+        }
+
         return Futures.successful(null);
     }
 }
index 8fa3a17f901541f79be1ec45a373ebe097ba69a1..81b6bccaf08ea0f35b5d4ed8c8a0fea8f3524796 100644 (file)
@@ -12,6 +12,7 @@ import static org.junit.Assert.assertNotNull;
 import akka.actor.ActorRef;
 import akka.actor.ActorSelection;
 import akka.actor.ActorSystem;
+import com.google.common.base.Optional;
 
 public class MockActorContext extends ActorContext {
 
@@ -30,19 +31,13 @@ public class MockActorContext extends ActorContext {
         super(actorSystem, shardManager, new MockClusterWrapper(), new MockConfiguration());
     }
 
-
-    @Override public Object executeShardOperation(String shardName,
-        Object message) {
-        return executeShardOperationResponse;
-    }
-
-    @Override public Object executeRemoteOperation(ActorSelection actor,
-        Object message) {
+    @Override public Object executeOperation(ActorSelection actor,
+                                             Object message) {
         return executeRemoteOperationResponse;
     }
 
-    @Override public ActorSelection findPrimary(String shardName) {
-        return null;
+    @Override public Optional<ActorSelection> findPrimaryShard(String shardName) {
+        return Optional.absent();
     }
 
     public void setExecuteShardOperationResponse(Object response){
@@ -74,14 +69,9 @@ public class MockActorContext extends ActorContext {
     }
 
     @Override
-    public Object executeLocalOperation(ActorRef actor,
-        Object message) {
+    public Object executeOperation(ActorRef actor,
+                                   Object message) {
         return this.executeLocalOperationResponse;
     }
 
-    @Override
-    public Object executeLocalShardOperation(String shardName,
-        Object message) {
-        return this.executeLocalShardOperationResponse;
-    }
 }
index 803aa03b7c722311588a5514c2191796b3b9278c..b80506d17d2efa61f5ae5673d3687dc67501bdee 100644 (file)
@@ -15,19 +15,31 @@ import akka.cluster.MemberStatus;
 import akka.cluster.UniqueAddress;
 import org.opendaylight.controller.cluster.datastore.ClusterWrapper;
 import scala.collection.JavaConversions;
-
 import java.util.HashSet;
 import java.util.Set;
 
 public class MockClusterWrapper implements ClusterWrapper{
 
-    @Override public void subscribeToMemberEvents(ActorRef actorRef) {
+    private String selfAddress = "akka.tcp://test@127.0.0.1:2550/user/member-1-shard-test-config";
+
+    @Override
+    public void subscribeToMemberEvents(ActorRef actorRef) {
     }
 
-    @Override public String getCurrentMemberName() {
+    @Override
+    public String getCurrentMemberName() {
         return "member-1";
     }
 
+    @Override
+    public String getSelfAddress() {
+        return selfAddress;
+    }
+
+    public void setSelfAddress(String selfAddress) {
+        this.selfAddress = selfAddress;
+    }
+
     public static void sendMemberUp(ActorRef to, String memberName, String address){
         to.tell(createMemberUp(memberName, address), null);
     }
index 4ddba2f1b9d773b3c4783d3e401fa7df43d32a0e..3bad4689506525bf683254534d44036ff8a61d7e 100644 (file)
@@ -21,7 +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");
+            .executeOperation(actorRef, "messages");
 
         Assert.assertNotNull(messages);
 
index ece312752d83164e845bce5e4e674499bdc3fd47..1f3732e36259c760ca4a910faf3650900012b440 100644 (file)
@@ -293,7 +293,7 @@ public class CompositeModel {
     Set<QName> childAugmentations = new HashSet<>();
     childAugmentations.add(AUG_QNAME);
     final YangInstanceIdentifier.AugmentationIdentifier augmentationIdentifier =
-        new YangInstanceIdentifier.AugmentationIdentifier(null, childAugmentations);
+        new YangInstanceIdentifier.AugmentationIdentifier(childAugmentations);
     final AugmentationNode augmentationNode =
         Builders.augmentationBuilder()
             .withNodeIdentifier(augmentationIdentifier)
index ac62974d290e5cb37744e39b085952a57aa28543..8f01a393c6eb28cb494fe89c063d5ab3085237be 100644 (file)
@@ -8,18 +8,24 @@
 package org.opendaylight.controller.config.yang.md.sal.dom.impl;
 
 import java.util.EnumMap;
+import java.util.List;
 import java.util.Map;
 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.AbstractMXBean;
 import org.opendaylight.controller.md.sal.common.util.jmx.ThreadExecutorStatsMXBeanImpl;
+import org.opendaylight.controller.md.sal.dom.broker.impl.DOMConcurrentDataCommitCoordinator;
 import org.opendaylight.controller.md.sal.dom.broker.impl.DOMDataBrokerImpl;
+import org.opendaylight.controller.md.sal.dom.broker.impl.DOMDataCommitCoordinatorImpl;
+import org.opendaylight.controller.md.sal.dom.broker.impl.DOMDataCommitExecutor;
 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.DurationStatisticsTracker;
 import org.opendaylight.yangtools.util.concurrent.DeadlockDetectingListeningExecutorService;
 import org.opendaylight.yangtools.util.concurrent.SpecialExecutors;
+import com.google.common.collect.Lists;
 
 /**
 *
@@ -65,17 +71,6 @@ public final class DomInmemoryDataBrokerModule extends
         datastores.put(LogicalDatastoreType.OPERATIONAL, operStore);
         datastores.put(LogicalDatastoreType.CONFIGURATION, configStore);
 
-        /*
-         * We use a single-threaded executor for commits with a bounded queue capacity. If the
-         * queue capacity is reached, subsequent commit tasks will be rejected and the commits will
-         * fail. This is done to relieve back pressure. This should be an extreme scenario - either
-         * there's deadlock(s) somewhere and the controller is unstable or some rogue component is
-         * continuously hammering commits too fast or the controller is just over-capacity for the
-         * system it's running on.
-         */
-        ExecutorService commitExecutor = SpecialExecutors.newBoundedSingleThreadExecutor(
-                getMaxDataBrokerCommitQueueSize(), "WriteTxCommit");
-
         /*
          * We use an executor for commit ListenableFuture callbacks that favors reusing available
          * threads over creating new threads at the expense of execution time. The assumption is
@@ -88,31 +83,65 @@ public final class DomInmemoryDataBrokerModule extends
                 getMaxDataBrokerFutureCallbackPoolSize(), getMaxDataBrokerFutureCallbackQueueSize(),
                 "CommitFutures");
 
-        DOMDataBrokerImpl newDataBroker = new DOMDataBrokerImpl(datastores,
-                new DeadlockDetectingListeningExecutorService(commitExecutor,
-                    TransactionCommitDeadlockException.DEADLOCK_EXCEPTION_SUPPLIER,
-                    listenableFutureExecutor));
+        final List<AbstractMXBean> mBeans = Lists.newArrayList();
+
+        DOMDataCommitExecutor commitCoordinator;
+        DurationStatisticsTracker commitStatsTracker = null;
+
+        if(getAllowConcurrentCommits()) {
+            DOMConcurrentDataCommitCoordinator coordinator =
+                    new DOMConcurrentDataCommitCoordinator(listenableFutureExecutor);
+            commitStatsTracker = coordinator.getCommitStatsTracker();
+            commitCoordinator = coordinator;
+        } else {
+            /*
+             * We use a single-threaded executor for commits with a bounded queue capacity. If the
+             * queue capacity is reached, subsequent commit tasks will be rejected and the commits will
+             * fail. This is done to relieve back pressure. This should be an extreme scenario - either
+             * there's deadlock(s) somewhere and the controller is unstable or some rogue component is
+             * continuously hammering commits too fast or the controller is just over-capacity for the
+             * system it's running on.
+             */
+            ExecutorService commitExecutor = SpecialExecutors.newBoundedSingleThreadExecutor(
+                    getMaxDataBrokerCommitQueueSize(), "WriteTxCommit");
+
+            DOMDataCommitCoordinatorImpl coordinator = new DOMDataCommitCoordinatorImpl(
+                    new DeadlockDetectingListeningExecutorService(commitExecutor,
+                            TransactionCommitDeadlockException.DEADLOCK_EXCEPTION_SUPPLIER,
+                            listenableFutureExecutor));
+
+            commitStatsTracker = coordinator.getCommitStatsTracker();
+            commitCoordinator = coordinator;
+
+            final AbstractMXBean commitExecutorStatsMXBean =
+                    ThreadExecutorStatsMXBeanImpl.create(commitExecutor, "CommitExecutorStats",
+                            JMX_BEAN_TYPE, null);
+            if(commitExecutorStatsMXBean != null) {
+                mBeans.add(commitExecutorStatsMXBean);
+            }
+        }
 
-        final CommitStatsMXBeanImpl commitStatsMXBean = new CommitStatsMXBeanImpl(
-                newDataBroker.getCommitStatsTracker(), JMX_BEAN_TYPE);
-        commitStatsMXBean.registerMBean();
+        DOMDataBrokerImpl newDataBroker = new DOMDataBrokerImpl(datastores, commitCoordinator);
+
+        if(commitStatsTracker != null) {
+            final CommitStatsMXBeanImpl commitStatsMXBean = new CommitStatsMXBeanImpl(
+                    commitStatsTracker, JMX_BEAN_TYPE);
+            commitStatsMXBean.registerMBean();
+            mBeans.add(commitStatsMXBean);
+        }
 
-        final AbstractMXBean commitExecutorStatsMXBean =
-                ThreadExecutorStatsMXBeanImpl.create(commitExecutor, "CommitExecutorStats",
-                        JMX_BEAN_TYPE, null);
         final AbstractMXBean commitFutureStatsMXBean =
                 ThreadExecutorStatsMXBeanImpl.create(listenableFutureExecutor,
                         "CommitFutureExecutorStats", JMX_BEAN_TYPE, null);
+        if(commitFutureStatsMXBean != null) {
+            mBeans.add(commitFutureStatsMXBean);
+        }
 
         newDataBroker.setCloseable(new AutoCloseable() {
             @Override
             public void close() {
-                commitStatsMXBean.unregisterMBean();
-                if (commitExecutorStatsMXBean != null) {
-                    commitExecutorStatsMXBean.unregisterMBean();
-                }
-                if (commitFutureStatsMXBean != null) {
-                    commitFutureStatsMXBean.unregisterMBean();
+                for(AbstractMXBean mBean: mBeans) {
+                    mBean.unregisterMBean();
                 }
             }
         });
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMConcurrentDataCommitCoordinator.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMConcurrentDataCommitCoordinator.java
new file mode 100644 (file)
index 0000000..605d71d
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ * 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;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+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.DurationStatisticsTracker;
+import org.opendaylight.yangtools.util.concurrent.MappingCheckedFuture;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
+import com.google.common.util.concurrent.AbstractFuture;
+import com.google.common.util.concurrent.AbstractListeningExecutorService;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Implementation of DOMDataCommitExecutor that coordinates transaction commits concurrently. The 3
+ * commit phases (canCommit, preCommit, and commit) are performed serially and non-blocking
+ * (ie async) per transaction but multiple transaction commits can run concurrent.
+ *
+ * @author Thomas Pantelis
+ */
+public class DOMConcurrentDataCommitCoordinator implements DOMDataCommitExecutor {
+
+    private static final String CAN_COMMIT = "CAN_COMMIT";
+    private static final String PRE_COMMIT = "PRE_COMMIT";
+    private static final String COMMIT = "COMMIT";
+
+    private static final Logger LOG = LoggerFactory.getLogger(DOMConcurrentDataCommitCoordinator.class);
+
+    private final DurationStatisticsTracker commitStatsTracker = DurationStatisticsTracker.createConcurrent();
+
+    /**
+     * This executor is used to execute Future listener callback Runnables async.
+     */
+    private final ExecutorService clientFutureCallbackExecutor;
+
+    /**
+     * This executor is re-used internally in calls to Futures#addCallback to avoid the overhead
+     * of Futures#addCallback creating a MoreExecutors#sameThreadExecutor for each call.
+     */
+    private final ExecutorService internalFutureCallbackExecutor = new SimpleSameThreadExecutor();
+
+    public DOMConcurrentDataCommitCoordinator(ExecutorService listenableFutureExecutor) {
+        this.clientFutureCallbackExecutor = Preconditions.checkNotNull(listenableFutureExecutor);
+    }
+
+    public DurationStatisticsTracker getCommitStatsTracker() {
+        return commitStatsTracker;
+    }
+
+    @Override
+    public CheckedFuture<Void, TransactionCommitFailedException> submit(DOMDataWriteTransaction transaction,
+            Iterable<DOMStoreThreePhaseCommitCohort> cohorts) {
+
+        Preconditions.checkArgument(transaction != null, "Transaction must not be null.");
+        Preconditions.checkArgument(cohorts != null, "Cohorts must not be null.");
+        LOG.debug("Tx: {} is submitted for execution.", transaction.getIdentifier());
+
+        final int cohortSize = Iterables.size(cohorts);
+        final AsyncNotifyingSettableFuture clientSubmitFuture =
+                new AsyncNotifyingSettableFuture(clientFutureCallbackExecutor);
+
+        doCanCommit(clientSubmitFuture, transaction, cohorts, cohortSize);
+
+        return MappingCheckedFuture.create(clientSubmitFuture,
+                TransactionCommitFailedExceptionMapper.COMMIT_ERROR_MAPPER);
+    }
+
+    private void doCanCommit(final AsyncNotifyingSettableFuture clientSubmitFuture,
+            final DOMDataWriteTransaction transaction,
+            final Iterable<DOMStoreThreePhaseCommitCohort> cohorts, final int cohortSize) {
+
+        final long startTime = System.nanoTime();
+
+        // Not using Futures.allAsList here to avoid its internal overhead.
+        final AtomicInteger remaining = new AtomicInteger(cohortSize);
+        FutureCallback<Boolean> futureCallback = new FutureCallback<Boolean>() {
+            @Override
+            public void onSuccess(Boolean result) {
+                if (result == null || !result) {
+                    handleException(clientSubmitFuture, transaction, cohorts, cohortSize,
+                            CAN_COMMIT, new TransactionCommitFailedException(
+                                            "Can Commit failed, no detailed cause available."));
+                } else {
+                    if(remaining.decrementAndGet() == 0) {
+                        // All cohorts completed successfully - we can move on to the preCommit phase
+                        doPreCommit(startTime, clientSubmitFuture, transaction, cohorts, cohortSize);
+                    }
+                }
+            }
+
+            @Override
+            public void onFailure(Throwable t) {
+                handleException(clientSubmitFuture, transaction, cohorts, cohortSize, CAN_COMMIT, t);
+            }
+        };
+
+        for(DOMStoreThreePhaseCommitCohort cohort: cohorts) {
+            ListenableFuture<Boolean> canCommitFuture = cohort.canCommit();
+            Futures.addCallback(canCommitFuture, futureCallback, internalFutureCallbackExecutor);
+        }
+    }
+
+    private void doPreCommit(final long startTime, final AsyncNotifyingSettableFuture clientSubmitFuture,
+            final DOMDataWriteTransaction transaction,
+            final Iterable<DOMStoreThreePhaseCommitCohort> cohorts, final int cohortSize) {
+
+        // Not using Futures.allAsList here to avoid its internal overhead.
+        final AtomicInteger remaining = new AtomicInteger(cohortSize);
+        FutureCallback<Void> futureCallback = new FutureCallback<Void>() {
+            @Override
+            public void onSuccess(Void notUsed) {
+                if(remaining.decrementAndGet() == 0) {
+                    // All cohorts completed successfully - we can move on to the commit phase
+                    doCommit(startTime, clientSubmitFuture, transaction, cohorts, cohortSize);
+                }
+            }
+
+            @Override
+            public void onFailure(Throwable t) {
+                handleException(clientSubmitFuture, transaction, cohorts, cohortSize, CAN_COMMIT, t);
+            }
+        };
+
+        for(DOMStoreThreePhaseCommitCohort cohort: cohorts) {
+            ListenableFuture<Void> preCommitFuture = cohort.preCommit();
+            Futures.addCallback(preCommitFuture, futureCallback, internalFutureCallbackExecutor);
+        }
+    }
+
+    private void doCommit(final long startTime, final AsyncNotifyingSettableFuture clientSubmitFuture,
+            final DOMDataWriteTransaction transaction,
+            final Iterable<DOMStoreThreePhaseCommitCohort> cohorts, final int cohortSize) {
+
+        // Not using Futures.allAsList here to avoid its internal overhead.
+        final AtomicInteger remaining = new AtomicInteger(cohortSize);
+        FutureCallback<Void> futureCallback = new FutureCallback<Void>() {
+            @Override
+            public void onSuccess(Void notUsed) {
+                if(remaining.decrementAndGet() == 0) {
+                    // All cohorts completed successfully - we're done.
+                    commitStatsTracker.addDuration(System.nanoTime() - startTime);
+
+                    clientSubmitFuture.set();
+                }
+            }
+
+            @Override
+            public void onFailure(Throwable t) {
+                handleException(clientSubmitFuture, transaction, cohorts, cohortSize, CAN_COMMIT, t);
+            }
+        };
+
+        for(DOMStoreThreePhaseCommitCohort cohort: cohorts) {
+            ListenableFuture<Void> commitFuture = cohort.commit();
+            Futures.addCallback(commitFuture, futureCallback, internalFutureCallbackExecutor);
+        }
+    }
+
+    private void handleException(final AsyncNotifyingSettableFuture clientSubmitFuture,
+            final DOMDataWriteTransaction transaction,
+            final Iterable<DOMStoreThreePhaseCommitCohort> cohorts, int cohortSize,
+            final String phase, final Throwable t) {
+
+        if(clientSubmitFuture.isDone()) {
+            // We must have had failures from multiple cohorts.
+            return;
+        }
+
+        LOG.warn("Tx: {} Error during phase {}, starting Abort", transaction.getIdentifier(), phase, t);
+        Exception e;
+        if(t instanceof Exception) {
+            e = (Exception)t;
+        } else {
+            e = new RuntimeException("Unexpected error occurred", t);
+        }
+
+        final TransactionCommitFailedException clientException =
+                TransactionCommitFailedExceptionMapper.CAN_COMMIT_ERROR_MAPPER.apply(e);
+
+        // Transaction failed - tell all cohorts to abort.
+
+        @SuppressWarnings("unchecked")
+        ListenableFuture<Void>[] canCommitFutures = new ListenableFuture[cohortSize];
+        int i = 0;
+        for(DOMStoreThreePhaseCommitCohort cohort: cohorts) {
+            canCommitFutures[i++] = cohort.abort();
+        }
+
+        ListenableFuture<List<Void>> combinedFuture = Futures.allAsList(canCommitFutures);
+        Futures.addCallback(combinedFuture, new FutureCallback<List<Void>>() {
+            @Override
+            public void onSuccess(List<Void> notUsed) {
+                // Propagate the original exception to the client.
+                clientSubmitFuture.setException(clientException);
+            }
+
+            @Override
+            public void onFailure(Throwable t) {
+                LOG.error("Tx: {} Error during Abort.", transaction.getIdentifier(), t);
+
+                // Propagate the original exception as that is what caused the Tx to fail and is
+                // what's interesting to the client.
+                clientSubmitFuture.setException(clientException);
+            }
+        }, internalFutureCallbackExecutor);
+    }
+
+    /**
+     * A settable future that uses an {@link Executor} to execute listener callback Runnables,
+     * registered via {@link #addListener}, asynchronously when this future completes. This is
+     * done to guarantee listener executions are off-loaded onto another thread to avoid blocking
+     * the thread that completed this future, as a common use case is to pass an executor that runs
+     * tasks in the same thread as the caller (ie MoreExecutors#sameThreadExecutor)
+     * to {@link #addListener}.
+     *
+     * FIXME: This class should probably be moved to yangtools common utils for re-usability and
+     * unified with AsyncNotifyingListenableFutureTask.
+     */
+    private static class AsyncNotifyingSettableFuture extends AbstractFuture<Void> {
+
+        /**
+         * ThreadLocal used to detect if the task completion thread is running the future listener Runnables.
+         */
+        private static final ThreadLocal<Boolean> ON_TASK_COMPLETION_THREAD_TL = new ThreadLocal<Boolean>();
+
+        private final ExecutorService listenerExecutor;
+
+        AsyncNotifyingSettableFuture(ExecutorService listenerExecutor) {
+            this.listenerExecutor = listenerExecutor;
+        }
+
+        @Override
+        public void addListener(final Runnable listener, final Executor executor) {
+            // Wrap the listener Runnable in a DelegatingRunnable. If the specified executor is one
+            // that runs tasks in the same thread as the caller submitting the task
+            // (e.g. {@link com.google.common.util.concurrent.MoreExecutors#sameThreadExecutor}) and
+            // the listener is executed from the #set methods, then the DelegatingRunnable will detect
+            // this via the ThreadLocal and submit the listener Runnable to the listenerExecutor.
+            //
+            // On the other hand, if this task is already complete, the call to ExecutionList#add in
+            // superclass will execute the listener Runnable immediately and, since the ThreadLocal
+            // won't be set, the DelegatingRunnable will run the listener Runnable inline.
+            super.addListener(new DelegatingRunnable(listener, listenerExecutor), executor);
+        }
+
+        boolean set() {
+            ON_TASK_COMPLETION_THREAD_TL.set(Boolean.TRUE);
+            try {
+                return super.set(null);
+            } finally {
+                ON_TASK_COMPLETION_THREAD_TL.set(null);
+            }
+        }
+
+        @Override
+        protected boolean setException(Throwable throwable) {
+            ON_TASK_COMPLETION_THREAD_TL.set(Boolean.TRUE);
+            try {
+                return super.setException(throwable);
+            } finally {
+                ON_TASK_COMPLETION_THREAD_TL.set(null);
+            }
+        }
+
+        private static final class DelegatingRunnable implements Runnable {
+            private final Runnable delegate;
+            private final Executor executor;
+
+            DelegatingRunnable(final Runnable delegate, final Executor executor) {
+                this.delegate = Preconditions.checkNotNull(delegate);
+                this.executor = Preconditions.checkNotNull(executor);
+            }
+
+            @Override
+            public void run() {
+                if (ON_TASK_COMPLETION_THREAD_TL.get() != null) {
+                    // We're running on the task completion thread so off-load to the executor.
+                    LOG.trace("Submitting ListenenableFuture Runnable from thread {} to executor {}",
+                            Thread.currentThread().getName(), executor);
+                    executor.execute(delegate);
+                } else {
+                    // We're not running on the task completion thread so run the delegate inline.
+                    LOG.trace("Executing ListenenableFuture Runnable on this thread: {}",
+                            Thread.currentThread().getName());
+                    delegate.run();
+                }
+            }
+        }
+    }
+
+    /**
+     * A simple same-thread executor without the internal locking overhead that
+     * MoreExecutors#sameThreadExecutor has. The #execute method is the only one of concern - we
+     * don't shutdown the executor so the other methods irrelevant.
+     */
+    private static class SimpleSameThreadExecutor extends AbstractListeningExecutorService {
+
+        @Override
+        public void execute(Runnable command) {
+            command.run();
+        }
+
+        @Override
+        public boolean awaitTermination(long arg0, TimeUnit arg1) throws InterruptedException {
+            return true;
+        }
+
+        @Override
+        public boolean isShutdown() {
+            return false;
+        }
+
+        @Override
+        public boolean isTerminated() {
+            return false;
+        }
+
+        @Override
+        public void shutdown() {
+        }
+
+        @Override
+        public List<Runnable> shutdownNow() {
+            return null;
+        }
+    }
+}
index 5fbf1270cc7110133637cdb70016f44356a388a3..3f7db01c6b3e0c09065c9c279be46a923a93df5a 100644 (file)
@@ -8,6 +8,7 @@
 package org.opendaylight.controller.md.sal.dom.broker.impl;
 
 import static com.google.common.base.Preconditions.checkState;
+import com.google.common.base.Preconditions;
 import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.ListeningExecutorService;
 import java.util.EnumMap;
@@ -25,7 +26,6 @@ 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;
@@ -35,25 +35,26 @@ public class DOMDataBrokerImpl extends AbstractDOMForwardedTransactionFactory<DO
 
     private static final Logger LOG = LoggerFactory.getLogger(DOMDataBrokerImpl.class);
 
-    private final DOMDataCommitCoordinatorImpl coordinator;
+    private final DOMDataCommitExecutor coordinator;
     private final AtomicLong txNum = new AtomicLong();
     private final AtomicLong chainNum = new AtomicLong();
     private volatile AutoCloseable closeable;
 
     public DOMDataBrokerImpl(final Map<LogicalDatastoreType, DOMStore> datastores,
             final ListeningExecutorService executor) {
+        this(datastores, new DOMDataCommitCoordinatorImpl(executor));
+    }
+
+    public DOMDataBrokerImpl(final Map<LogicalDatastoreType, DOMStore> datastores,
+            final DOMDataCommitExecutor coordinator) {
         super(datastores);
-        this.coordinator = new DOMDataCommitCoordinatorImpl(executor);
+        this.coordinator = Preconditions.checkNotNull(coordinator);
     }
 
     public void setCloseable(final AutoCloseable closeable) {
         this.closeable = closeable;
     }
 
-    public DurationStatsTracker getCommitStatsTracker() {
-        return coordinator.getCommitStatsTracker();
-    }
-
     @Override
     public void close() {
         super.close();
index 15d7b1d966e1a59e028616bb85f5670f5805860b..c1ecaa67dfbd9af34f022c110ae35bc5b9002f83 100644 (file)
@@ -20,7 +20,7 @@ import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
 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.DurationStatisticsTracker;
 import org.opendaylight.yangtools.util.concurrent.MappingCheckedFuture;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -42,7 +42,7 @@ import org.slf4j.LoggerFactory;
 public class DOMDataCommitCoordinatorImpl implements DOMDataCommitExecutor {
 
     private static final Logger LOG = LoggerFactory.getLogger(DOMDataCommitCoordinatorImpl.class);
-    private final DurationStatsTracker commitStatsTracker = new DurationStatsTracker();
+    private final DurationStatisticsTracker commitStatsTracker = DurationStatisticsTracker.createConcurrent();
     private final ListeningExecutorService executor;
 
     /**
@@ -56,7 +56,7 @@ public class DOMDataCommitCoordinatorImpl implements DOMDataCommitExecutor {
         this.executor = Preconditions.checkNotNull(executor, "executor must not be null.");
     }
 
-    public DurationStatsTracker getCommitStatsTracker() {
+    public DurationStatisticsTracker getCommitStatsTracker() {
         return commitStatsTracker;
     }
 
@@ -129,16 +129,16 @@ public class DOMDataCommitCoordinatorImpl implements DOMDataCommitExecutor {
                 AtomicReferenceFieldUpdater.newUpdater(CommitCoordinationTask.class, CommitPhase.class, "currentPhase");
         private final DOMDataWriteTransaction tx;
         private final Iterable<DOMStoreThreePhaseCommitCohort> cohorts;
-        private final DurationStatsTracker commitStatTracker;
+        private final DurationStatisticsTracker commitStatTracker;
         private final int cohortSize;
         private volatile CommitPhase currentPhase = CommitPhase.SUBMITTED;
 
         public CommitCoordinationTask(final DOMDataWriteTransaction transaction,
                 final Iterable<DOMStoreThreePhaseCommitCohort> cohorts,
-                final DurationStatsTracker commitStatTracker) {
+                final DurationStatisticsTracker commitStatsTracker) {
             this.tx = Preconditions.checkNotNull(transaction, "transaction must not be null");
             this.cohorts = Preconditions.checkNotNull(cohorts, "cohorts must not be null");
-            this.commitStatTracker = commitStatTracker;
+            this.commitStatTracker = commitStatsTracker;
             this.cohortSize = Iterables.size(cohorts);
         }
 
index 8aa97e72d1156fb1a8b19d1e3ca62ff715d11a95..dae14b5128f7794d86c50039818b664b6b186276 100644 (file)
@@ -21,7 +21,7 @@ import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCoh
  *
  *
  */
-interface DOMDataCommitExecutor {
+public interface DOMDataCommitExecutor {
 
     /**
      * Submits supplied transaction to be executed in context of provided
index f67f6b01488c4584dca6ba547ab8230b2fab8f94..0d5306faf7fbb4f479b8c63504ef40d5aca71c48 100644 (file)
@@ -9,9 +9,8 @@
 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;
+import org.opendaylight.yangtools.util.DurationStatisticsTracker;
 
 /**
  * Implementation of the CommitStatsMXBean interface.
@@ -20,7 +19,7 @@ import org.opendaylight.yangtools.util.DurationStatsTracker;
  */
 public class CommitStatsMXBeanImpl extends AbstractMXBean implements CommitStatsMXBean {
 
-    private final DurationStatsTracker commitStatsTracker;
+    private final DurationStatisticsTracker commitStatsTracker;
 
     /**
      * Constructor.
@@ -28,7 +27,7 @@ public class CommitStatsMXBeanImpl extends AbstractMXBean implements CommitStats
      * @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,
+    public CommitStatsMXBeanImpl(@Nonnull DurationStatisticsTracker commitStatsTracker,
             @Nonnull String mBeanType) {
         super("CommitStats", mBeanType, null);
         this.commitStatsTracker = commitStatsTracker;
index e81f71a7d2069014b511b1162168131633d62c1a..fa6d4961939b6f5bcbf4f5eb50d042ea9aa86556 100644 (file)
@@ -120,6 +120,14 @@ module opendaylight-sal-dom-broker-impl {
                 type uint16;
                 description "The maximum queue size for the data broker's commit executor.";
             }
+
+            leaf allow-concurrent-commits {
+                default false;
+                type boolean;
+                description "Specifies whether or not to allow 3-phrase commits to run concurrently.
+                    Use with caution. If set to true, the data store implementations must be prepared
+                    to handle concurrent commits. The default is false";
+            }
         }
     }
     
diff --git a/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMConcurrentDataCommitCoordinatorTest.java b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMConcurrentDataCommitCoordinatorTest.java
new file mode 100644 (file)
index 0000000..25d7df1
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * 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;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.inOrder;
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicReference;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InOrder;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+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 com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
+import com.google.common.util.concurrent.Uninterruptibles;
+
+/**
+ * Unit tests for DOMConcurrentDataCommitCoordinator.
+ *
+ * @author Thomas Pantelis
+ */
+public class DOMConcurrentDataCommitCoordinatorTest {
+
+    private final DOMDataWriteTransaction transaction = mock(DOMDataWriteTransaction.class);
+    private final DOMStoreThreePhaseCommitCohort mockCohort1 = mock(DOMStoreThreePhaseCommitCohort.class);
+    private final DOMStoreThreePhaseCommitCohort mockCohort2 = mock(DOMStoreThreePhaseCommitCohort.class);
+    private final ThreadPoolExecutor futureExecutor =
+            new ThreadPoolExecutor(0, 1, 5, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
+    private final DOMConcurrentDataCommitCoordinator coordinator =
+            new DOMConcurrentDataCommitCoordinator(futureExecutor);
+
+    @Before
+    public void setup() {
+        doReturn("tx").when(transaction).getIdentifier();
+    }
+
+    @After
+    public void tearDown() {
+        futureExecutor.shutdownNow();
+    }
+
+    @Test
+    public void testSuccessfulSubmitAsync() throws Throwable {
+        testSuccessfulSubmit(true);
+    }
+
+    @Test
+    public void testSuccessfulSubmitSync() throws Throwable {
+        testSuccessfulSubmit(false);
+    }
+
+    private void testSuccessfulSubmit(final boolean doAsync) throws Throwable {
+        final CountDownLatch asyncCanCommitContinue = new CountDownLatch(1);
+        Answer<ListenableFuture<Boolean>> asyncCanCommit = new Answer<ListenableFuture<Boolean>>() {
+            @Override
+            public ListenableFuture<Boolean> answer(InvocationOnMock invocation) {
+                final SettableFuture<Boolean> future = SettableFuture.create();
+                if(doAsync) {
+                    new Thread() {
+                        @Override
+                        public void run() {
+                            Uninterruptibles.awaitUninterruptibly(asyncCanCommitContinue,
+                                    10, TimeUnit.SECONDS);
+                            future.set(true);
+                        }
+                    }.start();
+                } else {
+                    future.set(true);
+                }
+
+                return future;
+            }
+        };
+
+        doAnswer(asyncCanCommit).when(mockCohort1).canCommit();
+        doReturn(Futures.immediateFuture(null)).when(mockCohort1).preCommit();
+        doReturn(Futures.immediateFuture(null)).when(mockCohort1).commit();
+
+        doReturn(Futures.immediateFuture(true)).when(mockCohort2).canCommit();
+        doReturn(Futures.immediateFuture(null)).when(mockCohort2).preCommit();
+        doReturn(Futures.immediateFuture(null)).when(mockCohort2).commit();
+
+        CheckedFuture<Void, TransactionCommitFailedException> future = coordinator.submit(
+                transaction, Arrays.asList(mockCohort1, mockCohort2));
+
+        final CountDownLatch doneLatch = new CountDownLatch(1);
+        final AtomicReference<Throwable> caughtEx = new AtomicReference<>();
+        Futures.addCallback(future, new FutureCallback<Void>() {
+            @Override
+            public void onSuccess(Void result) {
+                doneLatch.countDown();
+            }
+
+            @Override
+            public void onFailure(Throwable t) {
+                caughtEx.set(t);
+                doneLatch.countDown();
+            }
+        });
+
+        asyncCanCommitContinue.countDown();
+
+        assertEquals("Submit complete", true, doneLatch.await(5, TimeUnit.SECONDS));
+
+        if(caughtEx.get() != null) {
+            throw caughtEx.get();
+        }
+
+        assertEquals("Task count", doAsync ? 1 : 0, futureExecutor.getTaskCount());
+
+        InOrder inOrder = inOrder(mockCohort1, mockCohort2);
+        inOrder.verify(mockCohort1).canCommit();
+        inOrder.verify(mockCohort2).canCommit();
+        inOrder.verify(mockCohort1).preCommit();
+        inOrder.verify(mockCohort2).preCommit();
+        inOrder.verify(mockCohort1).commit();
+        inOrder.verify(mockCohort2).commit();
+    }
+
+    @Test
+    public void testSubmitWithNegativeCanCommitResponse() throws Exception {
+        doReturn(Futures.immediateFuture(true)).when(mockCohort1).canCommit();
+        doReturn(Futures.immediateFuture(null)).when(mockCohort1).abort();
+
+        doReturn(Futures.immediateFuture(false)).when(mockCohort2).canCommit();
+        doReturn(Futures.immediateFuture(null)).when(mockCohort2).abort();
+
+        DOMStoreThreePhaseCommitCohort mockCohort3 = mock(DOMStoreThreePhaseCommitCohort.class);
+        doReturn(Futures.immediateFuture(false)).when(mockCohort3).canCommit();
+        doReturn(Futures.immediateFuture(null)).when(mockCohort3).abort();
+
+        CheckedFuture<Void, TransactionCommitFailedException> future = coordinator.submit(
+                transaction, Arrays.asList(mockCohort1, mockCohort2, mockCohort3));
+
+        assertFailure(future, null, mockCohort1, mockCohort2, mockCohort3);
+    }
+
+    private void assertFailure(CheckedFuture<Void, TransactionCommitFailedException> future,
+            Exception expCause, DOMStoreThreePhaseCommitCohort... mockCohorts)
+                    throws Exception {
+        try {
+            future.checkedGet(5, TimeUnit.SECONDS);
+            fail("Expected TransactionCommitFailedException");
+        } catch (TransactionCommitFailedException e) {
+            if(expCause != null) {
+                assertSame("Expected cause", expCause, e.getCause());
+            }
+
+            InOrder inOrder = inOrder((Object[])mockCohorts);
+            for(DOMStoreThreePhaseCommitCohort c: mockCohorts) {
+                inOrder.verify(c).abort();
+            }
+        } catch (TimeoutException e) {
+            throw e;
+        }
+    }
+
+    @Test
+    public void testSubmitWithCanCommitException() throws Exception {
+        doReturn(Futures.immediateFuture(true)).when(mockCohort1).canCommit();
+        doReturn(Futures.immediateFuture(null)).when(mockCohort1).abort();
+
+        IllegalStateException cause = new IllegalStateException("mock");
+        doReturn(Futures.immediateFailedFuture(cause)).when(mockCohort2).canCommit();
+        doReturn(Futures.immediateFuture(null)).when(mockCohort2).abort();
+
+        CheckedFuture<Void, TransactionCommitFailedException> future = coordinator.submit(
+                transaction, Arrays.asList(mockCohort1, mockCohort2));
+
+        assertFailure(future, cause, mockCohort1, mockCohort2);
+    }
+
+    @Test
+    public void testSubmitWithPreCommitException() throws Exception {
+        doReturn(Futures.immediateFuture(true)).when(mockCohort1).canCommit();
+        doReturn(Futures.immediateFuture(null)).when(mockCohort1).preCommit();
+        doReturn(Futures.immediateFuture(null)).when(mockCohort1).abort();
+
+        doReturn(Futures.immediateFuture(true)).when(mockCohort2).canCommit();
+        IllegalStateException cause = new IllegalStateException("mock");
+        doReturn(Futures.immediateFailedFuture(cause)).when(mockCohort2).preCommit();
+        doReturn(Futures.immediateFuture(null)).when(mockCohort2).abort();
+
+        DOMStoreThreePhaseCommitCohort mockCohort3 = mock(DOMStoreThreePhaseCommitCohort.class);
+        doReturn(Futures.immediateFuture(true)).when(mockCohort3).canCommit();
+        doReturn(Futures.immediateFailedFuture(new IllegalStateException("mock2"))).
+                when(mockCohort3).preCommit();
+        doReturn(Futures.immediateFuture(null)).when(mockCohort3).abort();
+
+        CheckedFuture<Void, TransactionCommitFailedException> future = coordinator.submit(
+                transaction, Arrays.asList(mockCohort1, mockCohort2, mockCohort3));
+
+        assertFailure(future, cause, mockCohort1, mockCohort2, mockCohort3);
+    }
+
+    @Test
+    public void testSubmitWithCommitException() throws Exception {
+        doReturn(Futures.immediateFuture(true)).when(mockCohort1).canCommit();
+        doReturn(Futures.immediateFuture(null)).when(mockCohort1).preCommit();
+        doReturn(Futures.immediateFuture(null)).when(mockCohort1).commit();
+        doReturn(Futures.immediateFuture(null)).when(mockCohort1).abort();
+
+        doReturn(Futures.immediateFuture(true)).when(mockCohort2).canCommit();
+        doReturn(Futures.immediateFuture(null)).when(mockCohort2).preCommit();
+        IllegalStateException cause = new IllegalStateException("mock");
+        doReturn(Futures.immediateFailedFuture(cause)).when(mockCohort2).commit();
+        doReturn(Futures.immediateFuture(null)).when(mockCohort2).abort();
+
+        DOMStoreThreePhaseCommitCohort mockCohort3 = mock(DOMStoreThreePhaseCommitCohort.class);
+        doReturn(Futures.immediateFuture(true)).when(mockCohort3).canCommit();
+        doReturn(Futures.immediateFuture(null)).when(mockCohort3).preCommit();
+        doReturn(Futures.immediateFailedFuture(new IllegalStateException("mock2"))).
+                when(mockCohort3).commit();
+        doReturn(Futures.immediateFuture(null)).when(mockCohort3).abort();
+
+        CheckedFuture<Void, TransactionCommitFailedException> future = coordinator.submit(
+                transaction, Arrays.asList(mockCohort1, mockCohort2, mockCohort3));
+
+        assertFailure(future, cause, mockCohort1, mockCohort2, mockCohort3);
+    }
+
+    @Test
+    public void testSubmitWithAbortException() throws Exception {
+        doReturn(Futures.immediateFuture(true)).when(mockCohort1).canCommit();
+        doReturn(Futures.immediateFailedFuture(new IllegalStateException("mock abort error"))).
+                when(mockCohort1).abort();
+
+        IllegalStateException cause = new IllegalStateException("mock canCommit error");
+        doReturn(Futures.immediateFailedFuture(cause)).when(mockCohort2).canCommit();
+        doReturn(Futures.immediateFuture(null)).when(mockCohort2).abort();
+
+        CheckedFuture<Void, TransactionCommitFailedException> future = coordinator.submit(
+                transaction, Arrays.asList(mockCohort1, mockCohort2));
+
+        assertFailure(future, cause, mockCohort1, mockCohort2);
+    }
+}
index 4d239a93f7fe953f1fd6203a47fd3b44e247e483..05c4793218646a85d238bd9ba6d4fc74f8269090 100644 (file)
@@ -48,7 +48,7 @@ public class BackwardsCompatibleMountPointManagerTest {
 
     private BackwardsCompatibleMountPointManager compatibleMountPointManager;
     static final QName qName = QName.create("namespace", "12-12-1212", "mount");
-    static final YangInstanceIdentifier id = YangInstanceIdentifier.builder(qName).build();
+    static final YangInstanceIdentifier id = YangInstanceIdentifier.of(qName);
 
     @Before
     public void setUp() throws Exception {
index beab6d2fb1a0014e3dece9b1c07f77aa611ee090..ecea744d14418fdb03216dab312f82c1d0fad1c0 100644 (file)
@@ -30,6 +30,8 @@ public class XSQLAdapter extends Thread implements SchemaContextListener {
     private static final int SLEEP = 10000;
     private static XSQLAdapter a = new XSQLAdapter();
     private static PrintStream l = null;
+    private static String tmpDir = null;
+    private static File xqlLog = null;
     public boolean stopped = false;
     private List<String> elementHosts = new ArrayList<String>();
     private String username;
@@ -79,6 +81,12 @@ public class XSQLAdapter extends Thread implements SchemaContextListener {
         return a;
     }
 
+    public static File getXQLLogfile() {
+        tmpDir = System.getProperty("java.io.tmpdir");
+        xqlLog = new File(tmpDir + "/xql.log");
+        return xqlLog;
+    }
+
     public static void main(String args[]) {
         XSQLAdapter adapter = new XSQLAdapter();
         adapter.start();
@@ -90,7 +98,7 @@ public class XSQLAdapter extends Thread implements SchemaContextListener {
                 synchronized (XSQLAdapter.class) {
                     if (l == null) {
                         l = new PrintStream(
-                                new FileOutputStream("/tmp/xql.log"));
+                                new FileOutputStream(getXQLLogfile()));
                     }
                 }
             }
@@ -108,7 +116,7 @@ public class XSQLAdapter extends Thread implements SchemaContextListener {
                 synchronized (XSQLAdapter.class) {
                     if (l == null) {
                         l = new PrintStream(
-                                new FileOutputStream("/tmp/xql.log"));
+                                new FileOutputStream(getXQLLogfile()));
                     }
                 }
             }
diff --git a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ChainedTransactionCommitImpl.java b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ChainedTransactionCommitImpl.java
new file mode 100644 (file)
index 0000000..5b0f739
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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 com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
+
+final class ChainedTransactionCommitImpl implements DOMStoreThreePhaseCommitCohort {
+    private final SnapshotBackedWriteTransaction transaction;
+    private final DOMStoreThreePhaseCommitCohort delegate;
+    private final DOMStoreTransactionChainImpl txChain;
+
+    protected ChainedTransactionCommitImpl(final SnapshotBackedWriteTransaction transaction,
+            final DOMStoreThreePhaseCommitCohort delegate, final DOMStoreTransactionChainImpl txChain) {
+        this.transaction = Preconditions.checkNotNull(transaction);
+        this.delegate = Preconditions.checkNotNull(delegate);
+        this.txChain = Preconditions.checkNotNull(txChain);
+    }
+
+    @Override
+    public ListenableFuture<Boolean> canCommit() {
+        return delegate.canCommit();
+    }
+
+    @Override
+    public ListenableFuture<Void> preCommit() {
+        return delegate.preCommit();
+    }
+
+    @Override
+    public ListenableFuture<Void> abort() {
+        return delegate.abort();
+    }
+
+    @Override
+    public ListenableFuture<Void> commit() {
+        ListenableFuture<Void> commitFuture = delegate.commit();
+        Futures.addCallback(commitFuture, new FutureCallback<Void>() {
+            @Override
+            public void onFailure(final Throwable t) {
+                txChain.onTransactionFailed(transaction, t);
+            }
+
+            @Override
+            public void onSuccess(final Void result) {
+                txChain.onTransactionCommited(transaction);
+            }
+        });
+        return commitFuture;
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/DOMStoreTransactionChainImpl.java b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/DOMStoreTransactionChainImpl.java
new file mode 100644 (file)
index 0000000..3f731cf
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * 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 java.util.AbstractMap.SimpleEntry;
+import java.util.Map.Entry;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+import org.opendaylight.controller.md.sal.dom.store.impl.SnapshotBackedWriteTransaction.TransactionReadyPrototype;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class DOMStoreTransactionChainImpl extends TransactionReadyPrototype implements DOMStoreTransactionChain {
+    private static abstract class State {
+        /**
+         * Allocate a new snapshot.
+         *
+         * @return A new snapshot
+         */
+        protected abstract DataTreeSnapshot getSnapshot();
+    }
+
+    private static final class Idle extends State {
+        private final InMemoryDOMDataStore store;
+
+        Idle(final InMemoryDOMDataStore store) {
+            this.store = Preconditions.checkNotNull(store);
+        }
+
+        @Override
+        protected DataTreeSnapshot getSnapshot() {
+            return store.takeSnapshot();
+        }
+    }
+
+    /**
+     * We have a transaction out there.
+     */
+    private static final class Allocated extends State {
+        private static final AtomicReferenceFieldUpdater<Allocated, DataTreeSnapshot> SNAPSHOT_UPDATER =
+                AtomicReferenceFieldUpdater.newUpdater(Allocated.class, DataTreeSnapshot.class, "snapshot");
+        private final DOMStoreWriteTransaction transaction;
+        private volatile DataTreeSnapshot snapshot;
+
+        Allocated(final DOMStoreWriteTransaction transaction) {
+            this.transaction = Preconditions.checkNotNull(transaction);
+        }
+
+        public DOMStoreWriteTransaction getTransaction() {
+            return transaction;
+        }
+
+        @Override
+        protected DataTreeSnapshot getSnapshot() {
+            final DataTreeSnapshot ret = snapshot;
+            Preconditions.checkState(ret != null, "Previous transaction %s is not ready yet", transaction.getIdentifier());
+            return ret;
+        }
+
+        void setSnapshot(final DataTreeSnapshot snapshot) {
+            final boolean success = SNAPSHOT_UPDATER.compareAndSet(this, null, snapshot);
+            Preconditions.checkState(success, "Transaction %s has already been marked as ready", transaction.getIdentifier());
+        }
+    }
+
+    /**
+     * Chain is logically shut down, no further allocation allowed.
+     */
+    private static final class Shutdown extends State {
+        private final String message;
+
+        Shutdown(final String message) {
+            this.message = Preconditions.checkNotNull(message);
+        }
+
+        @Override
+        protected DataTreeSnapshot getSnapshot() {
+            throw new IllegalStateException(message);
+        }
+    }
+
+    private static final AtomicReferenceFieldUpdater<DOMStoreTransactionChainImpl, State> STATE_UPDATER =
+            AtomicReferenceFieldUpdater.newUpdater(DOMStoreTransactionChainImpl.class, State.class, "state");
+    private static final Logger LOG = LoggerFactory.getLogger(DOMStoreTransactionChainImpl.class);
+    private static final Shutdown CLOSED = new Shutdown("Transaction chain is closed");
+    private static final Shutdown FAILED = new Shutdown("Transaction chain has failed");
+    private final InMemoryDOMDataStore store;
+    private final Idle idleState;
+    private volatile State state;
+
+    DOMStoreTransactionChainImpl(final InMemoryDOMDataStore store) {
+        this.store = Preconditions.checkNotNull(store);
+        idleState = new Idle(store);
+        state = idleState;
+    }
+
+    private Entry<State, DataTreeSnapshot> getSnapshot() {
+        final State localState = state;
+        return new SimpleEntry<>(localState, localState.getSnapshot());
+    }
+
+    private boolean recordTransaction(final State expected, final DOMStoreWriteTransaction transaction) {
+        final State state = new Allocated(transaction);
+        return STATE_UPDATER.compareAndSet(this, expected, state);
+    }
+
+    @Override
+    public DOMStoreReadTransaction newReadOnlyTransaction() {
+        final Entry<State, DataTreeSnapshot> entry = getSnapshot();
+        return new SnapshotBackedReadTransaction(store.nextIdentifier(), store.getDebugTransactions(), entry.getValue());
+    }
+
+    @Override
+    public DOMStoreReadWriteTransaction newReadWriteTransaction() {
+        Entry<State, DataTreeSnapshot> entry;
+        DOMStoreReadWriteTransaction ret;
+
+        do {
+            entry = getSnapshot();
+            ret = new SnapshotBackedReadWriteTransaction(store.nextIdentifier(),
+                store.getDebugTransactions(), entry.getValue(), this);
+        } while (!recordTransaction(entry.getKey(), ret));
+
+        return ret;
+    }
+
+    @Override
+    public DOMStoreWriteTransaction newWriteOnlyTransaction() {
+        Entry<State, DataTreeSnapshot> entry;
+        DOMStoreWriteTransaction ret;
+
+        do {
+            entry = getSnapshot();
+            ret = new SnapshotBackedWriteTransaction(store.nextIdentifier(),
+                store.getDebugTransactions(), entry.getValue(), this);
+        } while (!recordTransaction(entry.getKey(), ret));
+
+        return ret;
+    }
+
+    @Override
+    protected void transactionAborted(final SnapshotBackedWriteTransaction tx) {
+        final State localState = state;
+        if (localState instanceof Allocated) {
+            final Allocated allocated = (Allocated)localState;
+            if (allocated.getTransaction().equals(tx)) {
+                final boolean success = STATE_UPDATER.compareAndSet(this, localState, idleState);
+                if (!success) {
+                    LOG.info("State already transitioned from {} to {}", localState, state);
+                }
+            }
+        }
+    }
+
+    @Override
+    protected DOMStoreThreePhaseCommitCohort transactionReady(final SnapshotBackedWriteTransaction tx, final DataTreeModification tree) {
+        final State localState = state;
+
+        if (localState instanceof Allocated) {
+            final Allocated allocated = (Allocated)localState;
+            final DOMStoreWriteTransaction transaction = allocated.getTransaction();
+            Preconditions.checkState(tx.equals(transaction), "Mis-ordered ready transaction %s last allocated was %s", tx, transaction);
+            allocated.setSnapshot(tree);
+        } else {
+            LOG.debug("Ignoring transaction {} readiness due to state {}", tx, localState);
+        }
+
+        return new ChainedTransactionCommitImpl(tx, store.transactionReady(tx, tree), this);
+    }
+
+    @Override
+    public void close() {
+        final State localState = state;
+
+        do {
+            Preconditions.checkState(!CLOSED.equals(localState), "Transaction chain {} has been closed", this);
+
+            if (FAILED.equals(localState)) {
+                LOG.debug("Ignoring user close in failed state");
+                return;
+            }
+        } while (!STATE_UPDATER.compareAndSet(this, localState, CLOSED));
+    }
+
+    void onTransactionFailed(final SnapshotBackedWriteTransaction transaction, final Throwable t) {
+        LOG.debug("Transaction chain {} failed on transaction {}", this, transaction, t);
+        state = FAILED;
+    }
+
+    void onTransactionCommited(final SnapshotBackedWriteTransaction transaction) {
+        // If the committed transaction was the one we allocated last,
+        // we clear it and the ready snapshot, so the next transaction
+        // allocated refers to the data tree directly.
+        final State localState = state;
+
+        if (!(localState instanceof Allocated)) {
+            LOG.debug("Ignoring successful transaction {} in state {}", transaction, localState);
+            return;
+        }
+
+        final Allocated allocated = (Allocated)localState;
+        final DOMStoreWriteTransaction tx = allocated.getTransaction();
+        if (!tx.equals(transaction)) {
+            LOG.debug("Ignoring non-latest successful transaction {} in state {}", transaction, allocated);
+            return;
+        }
+
+        if (!STATE_UPDATER.compareAndSet(this, localState, idleState)) {
+            LOG.debug("Transaction chain {} has already transitioned from {} to {}, not making it idle", this, localState, state);
+        }
+    }
+}
\ No newline at end of file
index 74fa73afb92f869f7cb2e945a625d489b71e71c2..213f60e951cc41794864fcb1fd813a1958469728 100644 (file)
@@ -10,7 +10,6 @@ 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;
@@ -18,7 +17,6 @@ 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.AsyncDataChangeListener;
 import org.opendaylight.controller.md.sal.common.api.data.OptimisticLockFailedException;
@@ -142,7 +140,7 @@ public class InMemoryDOMDataStore extends TransactionReadyPrototype implements D
 
     @Override
     public DOMStoreTransactionChain createTransactionChain() {
-        return new DOMStoreTransactionChainImpl();
+        return new DOMStoreTransactionChainImpl(this);
     }
 
     @Override
@@ -164,10 +162,14 @@ public class InMemoryDOMDataStore extends TransactionReadyPrototype implements D
         }
     }
 
-    boolean getDebugTransactions() {
+    public final boolean getDebugTransactions() {
         return debugTransactions;
     }
 
+    final DataTreeSnapshot takeSnapshot() {
+        return dataTree.takeSnapshot();
+    }
+
     @Override
     public <L extends AsyncDataChangeListener<YangInstanceIdentifier, NormalizedNode<?, ?>>> ListenerRegistration<L> registerChangeListener(
             final YangInstanceIdentifier path, final L listener, final DataChangeScope scope) {
@@ -219,156 +221,11 @@ public class InMemoryDOMDataStore extends TransactionReadyPrototype implements D
         return new ThreePhaseCommitImpl(tx, tree);
     }
 
-    private Object nextIdentifier() {
+    Object nextIdentifier() {
         return name + "-" + txCounter.getAndIncrement();
     }
 
-    private class DOMStoreTransactionChainImpl extends TransactionReadyPrototype implements DOMStoreTransactionChain {
-        @GuardedBy("this")
-        private SnapshotBackedWriteTransaction allocatedTransaction;
-        @GuardedBy("this")
-        private DataTreeSnapshot readySnapshot;
-        @GuardedBy("this")
-        private boolean chainFailed = false;
-
-        @GuardedBy("this")
-        private void checkFailed() {
-            Preconditions.checkState(!chainFailed, "Transaction chain is failed.");
-        }
-
-        @GuardedBy("this")
-        private DataTreeSnapshot getSnapshot() {
-            checkFailed();
-
-            if (allocatedTransaction != null) {
-                Preconditions.checkState(readySnapshot != null, "Previous transaction %s is not ready yet", allocatedTransaction.getIdentifier());
-                return readySnapshot;
-            } else {
-                return dataTree.takeSnapshot();
-            }
-        }
-
-        @GuardedBy("this")
-        private <T extends SnapshotBackedWriteTransaction> T recordTransaction(final T transaction) {
-            allocatedTransaction = transaction;
-            readySnapshot = null;
-            return transaction;
-        }
-
-        @Override
-        public synchronized DOMStoreReadTransaction newReadOnlyTransaction() {
-            final DataTreeSnapshot snapshot = getSnapshot();
-            return new SnapshotBackedReadTransaction(nextIdentifier(), getDebugTransactions(), snapshot);
-        }
-
-        @Override
-        public synchronized DOMStoreReadWriteTransaction newReadWriteTransaction() {
-            final DataTreeSnapshot snapshot = getSnapshot();
-            return recordTransaction(new SnapshotBackedReadWriteTransaction(nextIdentifier(),
-                    getDebugTransactions(), snapshot, this));
-        }
-
-        @Override
-        public synchronized DOMStoreWriteTransaction newWriteOnlyTransaction() {
-            final DataTreeSnapshot snapshot = getSnapshot();
-            return recordTransaction(new SnapshotBackedWriteTransaction(nextIdentifier(),
-                    getDebugTransactions(), snapshot, this));
-        }
-
-        @Override
-        protected synchronized void transactionAborted(final SnapshotBackedWriteTransaction tx) {
-            if (tx.equals(allocatedTransaction)) {
-                Preconditions.checkState(readySnapshot == null, "Unexpected abort of transaction %s with ready snapshot %s", tx, readySnapshot);
-                allocatedTransaction = null;
-            }
-        }
-
-        @Override
-        protected synchronized DOMStoreThreePhaseCommitCohort transactionReady(final SnapshotBackedWriteTransaction tx, final DataTreeModification tree) {
-            Preconditions.checkState(tx.equals(allocatedTransaction), "Mis-ordered ready transaction %s last allocated was %s", tx, allocatedTransaction);
-            if (readySnapshot != null) {
-                // The snapshot should have been cleared
-                LOG.warn("Uncleared snapshot {} encountered, overwritten with transaction {} snapshot {}", readySnapshot, tx, tree);
-            }
-
-            final DOMStoreThreePhaseCommitCohort cohort = InMemoryDOMDataStore.this.transactionReady(tx, tree);
-            readySnapshot = tree;
-            return new ChainedTransactionCommitImpl(tx, cohort, this);
-        }
-
-        @Override
-        public void close() {
-            // FIXME: this call doesn't look right here - listeningExecutor is shared and owned
-            // by the outer class.
-            //listeningExecutor.shutdownNow();
-        }
-
-        protected synchronized void onTransactionFailed(final SnapshotBackedWriteTransaction transaction,
-                final Throwable t) {
-            chainFailed = true;
-        }
-
-        public synchronized void onTransactionCommited(final SnapshotBackedWriteTransaction transaction) {
-            // If the committed transaction was the one we allocated last,
-            // we clear it and the ready snapshot, so the next transaction
-            // allocated refers to the data tree directly.
-            if (transaction.equals(allocatedTransaction)) {
-                if (readySnapshot == null) {
-                    LOG.warn("Transaction {} committed while no ready snapshot present", transaction);
-                }
-
-                allocatedTransaction = null;
-                readySnapshot = null;
-            }
-        }
-    }
-
-    private static class ChainedTransactionCommitImpl implements DOMStoreThreePhaseCommitCohort {
-        private final SnapshotBackedWriteTransaction transaction;
-        private final DOMStoreThreePhaseCommitCohort delegate;
-        private final DOMStoreTransactionChainImpl txChain;
-
-        protected ChainedTransactionCommitImpl(final SnapshotBackedWriteTransaction transaction,
-                final DOMStoreThreePhaseCommitCohort delegate, final DOMStoreTransactionChainImpl txChain) {
-            this.transaction = transaction;
-            this.delegate = delegate;
-            this.txChain = txChain;
-        }
-
-        @Override
-        public ListenableFuture<Boolean> canCommit() {
-            return delegate.canCommit();
-        }
-
-        @Override
-        public ListenableFuture<Void> preCommit() {
-            return delegate.preCommit();
-        }
-
-        @Override
-        public ListenableFuture<Void> abort() {
-            return delegate.abort();
-        }
-
-        @Override
-        public ListenableFuture<Void> commit() {
-            ListenableFuture<Void> commitFuture = delegate.commit();
-            Futures.addCallback(commitFuture, new FutureCallback<Void>() {
-                @Override
-                public void onFailure(final Throwable t) {
-                    txChain.onTransactionFailed(transaction, t);
-                }
-
-                @Override
-                public void onSuccess(final Void result) {
-                    txChain.onTransactionCommited(transaction);
-                }
-            });
-            return commitFuture;
-        }
-    }
-
-    private class ThreePhaseCommitImpl implements DOMStoreThreePhaseCommitCohort {
+    private final class ThreePhaseCommitImpl implements DOMStoreThreePhaseCommitCohort {
         private final SnapshotBackedWriteTransaction transaction;
         private final DataTreeModification modification;
 
index 5fbb60555814f11267bba0012a650adf4b040b0d..552e2bbd190d154280e1a8ce7a3bc22d89de908b 100644 (file)
@@ -29,7 +29,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 class JsonToCompositeNodeReader {
-    private static final Logger LOG = LoggerFactory.getLogger(JsonReader.class);
+    private static final Logger LOG = LoggerFactory.getLogger(JsonToCompositeNodeReader.class);
     private static final Splitter COLON_SPLITTER = Splitter.on(':');
 
     private JsonToCompositeNodeReader() {
@@ -113,14 +113,29 @@ class JsonToCompositeNodeReader {
         }
     }
 
+    /**
+     * Transform input value to URI instance.
+     *
+     * Input string has to be in format moduleName:localName. moduleName part is then transformed to URI instance.
+     * If moduleName part contains character like "<" or ">" then null value is returned because they
+     * aren't valid URI characters.
+     *
+     * @param jsonElementName
+     *  value in format moduleName:localName
+     * @return
+     */
     private static URI getNamespaceFor(final String jsonElementName) {
         final Iterator<String> it = COLON_SPLITTER.split(jsonElementName).iterator();
 
-        // The string needs to me in form "moduleName:localName"
+        // The string needs to be in form "moduleName:localName"
         if (it.hasNext()) {
             final String maybeURI = it.next();
             if (Iterators.size(it) == 1) {
-                return URI.create(maybeURI);
+                try {
+                    return URI.create(maybeURI);
+                } catch (IllegalArgumentException e) {
+                    LOG.debug("Value {} couldn't be interpreted as URI.", maybeURI);
+                }
             }
         }
 
@@ -144,7 +159,7 @@ class JsonToCompositeNodeReader {
             }
         }
 
-        // it could be identityref Built-In Type
+        // it could be identityref Built-In Type therefore it is necessary to look at value as module_name:local_name
         URI namespace = getNamespaceFor(value);
         if (namespace != null) {
             return new IdentityValuesDTO(namespace.toString(), getLocalNameFor(value), null, value);
index 3a6de300a0463da6cec1b0a2466375211b5adabd..bab26dfc012b1a620f2e0a619ef3d93d10b0bb2e 100644 (file)
@@ -16,7 +16,6 @@ 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;
@@ -28,6 +27,8 @@ 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.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
@@ -72,7 +73,9 @@ public class NormalizedNodeXmlBodyWriter implements MessageBodyWriter<Normalized
             WebApplicationException {
         InstanceIdentifierContext pathContext = t.getInstanceIdentifierContext();
         if (t.getData() == null) {
-            throw new RestconfDocumentedException(Response.Status.NOT_FOUND);
+            throw new RestconfDocumentedException(
+                    "Request could not be completed because the relevant data model content does not exist.",
+                    ErrorType.APPLICATION, ErrorTag.DATA_MISSING);
         }
 
         XMLStreamWriter xmlWriter;
index 8dbc5b50ee5dbd8ac374ef7d1452384442923085..3988a495cb15de246c29647bbf042d7a40be8702 100644 (file)
@@ -231,7 +231,7 @@ public class BrokerFacade {
     private CheckedFuture<Void, TransactionCommitFailedException> deleteDataViaTransaction(
             final DOMDataWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
             YangInstanceIdentifier path) {
-        LOG.info("Delete " + datastore.name() + " via Restconf: {}", path);
+        LOG.trace("Delete " + datastore.name() + " via Restconf: {}", path);
         writeTransaction.delete(datastore, path);
         return writeTransaction.submit();
     }
index 3699e4924fe25ca2c8a4b1399fe005376de3a86d..d65cb1bdbfe48bc02d132faab0e2cf82756cb785 100644 (file)
@@ -422,4 +422,36 @@ public class JsonToCnSnTest {
         assertTrue(exceptionMessage.contains("Root element of Json has to be Object"));
     }
 
+    /**
+     * Tests case when JSON input data value is in format string1:string2 and first string contain characters "<" or ">" (invalid URI characters).
+     *
+     * During loading data it is also interpreting as data value in moduleName:localName (potential leafref value).
+     * ModuleName part is transformed to URI which causes exception which is caught and URI value is null which cause that potential value in simple node is
+     * simple string (value from JSON input) and not IdentityValueDTO instance which is used for leaf-ref candidates.
+     */
+    @Test
+    public void invalidUriCharacterInValue() {
+        final Node<?> rootNode = TestUtils.readInputToCnSn("/json-to-cnsn/invalid-uri-character-in-value.json", true,
+                    JsonToCompositeNodeProvider.INSTANCE);
+
+        assertTrue(rootNode instanceof CompositeNode);
+        Node<?> lf1 = null;
+        Node<?> lf2 = null;
+        for(Node<?> child : ((CompositeNode)rootNode).getChildren()) {
+            if (child.getNodeType().getLocalName().equals("lf1")) {
+                lf1 = child;
+            } else if (child.getNodeType().getLocalName().equals("lf2")) {
+                lf2 = child;
+            }
+        }
+
+        assertNotNull(lf1);
+        assertNotNull(lf2);
+        assertTrue(lf1 instanceof SimpleNode<?>);
+        assertTrue(lf2 instanceof SimpleNode<?>);
+
+        assertEquals("module<Name:value lf1", ((SimpleNode<?>) lf1).getValue());
+        assertEquals("module>Name:value lf2", ((SimpleNode<?>) lf2).getValue());
+    }
+
 }
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/invalid-uri-character-in-value.json b/opendaylight/md-sal/sal-rest-connector/src/test/resources/json-to-cnsn/invalid-uri-character-in-value.json
new file mode 100644 (file)
index 0000000..6a78e9f
--- /dev/null
@@ -0,0 +1,6 @@
+{
+    "moduleName:cont":{
+       "lf1":"module<Name:value lf1",
+       "lf2":"module>Name:value lf2"
+       }
+}
\ No newline at end of file
index f4274870c9305d84f1ee53798bb934f8721748a4..3b503ebba35c016382d390ad695c4bda7c553ef2 100644 (file)
@@ -146,8 +146,10 @@ public class ModelGenerator {
 
         for (DataSchemaNode childNode : module.getChildNodes()) {
             // For every container and list in the module
-            processDataNodeContainer((DataNodeContainer) childNode, moduleName, models, true, schemaContext);
-            processDataNodeContainer((DataNodeContainer) childNode, moduleName, models, false, schemaContext);
+            if (childNode instanceof ContainerSchemaNode || childNode instanceof ListSchemaNode) {
+                processDataNodeContainer((DataNodeContainer) childNode, moduleName, models, true, schemaContext);
+                processDataNodeContainer((DataNodeContainer) childNode, moduleName, models, false, schemaContext);
+            }
         }
 
     }
@@ -306,6 +308,9 @@ public class ModelGenerator {
                 property.put(TYPE_KEY, childNode instanceof ListSchemaNode ? ARRAY_TYPE : OBJECT_TYPE);
                 property.put(ITEMS_KEY, items);
                 properties.put(childNode.getQName().getLocalName(), property);
+            } else if (childNode instanceof LeafSchemaNode){
+                JSONObject property = processLeafNode((LeafSchemaNode)childNode);
+                properties.put(childNode.getQName().getLocalName(), property);
             }
         }
         return properties;
diff --git a/opendaylight/md-sal/sal-rest-docgen/src/test/java/org/opendaylight/controller/sal/rest/doc/impl/ModelGeneratorTest.java b/opendaylight/md-sal/sal-rest-docgen/src/test/java/org/opendaylight/controller/sal/rest/doc/impl/ModelGeneratorTest.java
new file mode 100644 (file)
index 0000000..5918a0e
--- /dev/null
@@ -0,0 +1,45 @@
+package org.opendaylight.controller.sal.rest.doc.impl;
+
+import com.google.common.base.Preconditions;
+import org.json.JSONObject;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+
+import java.io.File;
+import java.util.HashSet;
+import java.util.Map;
+
+
+public class ModelGeneratorTest {
+
+    private DocGenTestHelper helper;
+    private SchemaContext schemaContext;
+
+    @Before
+    public void setUp() throws Exception {
+        helper = new DocGenTestHelper();
+        helper.setUp();
+        schemaContext = new YangParserImpl().resolveSchemaContext(new HashSet<Module>(helper.getModules().values()));
+    }
+
+    @Test
+    public void testConvertToJsonSchema() throws Exception {
+
+        Preconditions.checkArgument(helper.getModules() != null, "No modules found");
+
+        ModelGenerator generator = new ModelGenerator();
+
+        for (Map.Entry<File, Module> m : helper.getModules().entrySet()) {
+            if (m.getKey().getAbsolutePath().endsWith("opflex.yang")) {
+
+                JSONObject jsonObject = generator.convertToJsonSchema(m.getValue(), schemaContext);
+                Assert.assertNotNull(jsonObject);
+            }
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-docgen/src/test/resources/yang/opflex.yang b/opendaylight/md-sal/sal-rest-docgen/src/test/resources/yang/opflex.yang
new file mode 100644 (file)
index 0000000..8e598dd
--- /dev/null
@@ -0,0 +1,50 @@
+module opflex {
+    yang-version 1;
+
+    namespace "urn:opendaylight:groupbasedpolicy:opflex";
+    prefix "opflex";
+
+
+
+
+
+    description
+        "This module defines the group-based policy OpFlex renderer model.";
+
+    revision "2014-05-28" {
+        description
+            "Initial revision.";
+    }
+
+    typedef serialization {
+        description
+            "The serialization to use for OpFlex messages.";
+
+        type enumeration {
+            enum json {
+                description
+                "JSON 1.0 serialization.";
+            }
+            enum xml {
+                description
+                "XML serialization.";
+            }
+            enum binary {
+                description
+                "OpFlex binary serialization.";
+            }
+        }
+    }
+
+    // ******************
+    // Configuration Data
+    // ******************
+    leaf domain {
+        description
+            "The OpFlex administrative domain.";
+
+        config true;
+
+        type string;
+    }
+}
\ No newline at end of file
index 20bbd78622eb839d9679e3909769ed188ebd3c22..ffddc8c3daa0f36f8ea51a2e4e39000b44438fe6 100644 (file)
@@ -20,11 +20,19 @@ module toaster {
         "Toaster module in progress.";
     }
 
+    leaf domain {
+        description
+            "Toaster domain.";
+
+        config true;
+
+        type string;
+    }
 
     identity toast-type {
       description
           "Base for all bread types supported by the toaster.
-           New bread types not listed here nay be added in the 
+           New bread types not listed here nay be added in the
            future.";
     }
 
@@ -72,7 +80,7 @@ module toaster {
         "Indicates the toaster service is available";
       description
         "Top-level container for all toaster database objects.";
-        
+
       leaf testToasterBits {
          type bits {
              bit testbit1 {
@@ -84,21 +92,21 @@ module toaster {
          }
          default "testbit2";
      }
-     
+
      leaf testUnion {
         type union {
          type int32;
          type string;
         }
-        
-     } 
-     
+
+     }
+
      leaf-list allow-user  {
           type string;
           description "A list of user name patterns to allow";
-        
+
         }
-        
+
         choice how {
              default interval;
              case interval {
@@ -123,14 +131,14 @@ module toaster {
                      type string;
                  }
              }
-         } 
-        
+         }
+
       leaf toasterManufacturer {
         type DisplayString;
         config false;
         mandatory true;
         description
-          "The name of the toaster's manufacturer. For instance, 
+          "The name of the toaster's manufacturer. For instance,
                 Microsoft Toaster.";
       }
 
@@ -161,7 +169,7 @@ module toaster {
         config false;
         mandatory true;
         description
-          "This variable indicates the current state of 
+          "This variable indicates the current state of
                the toaster.";
       }
     }
@@ -169,11 +177,11 @@ module toaster {
     rpc make-toast {
       description
         "Make some toast.
-           The toastDone notification will be sent when 
+           The toastDone notification will be sent when
            the toast is finished.
            An 'in-use' error will be returned if toast
            is already being made.
-           A 'resource-denied' error will be returned 
+           A 'resource-denied' error will be returned
            if the toaster service is disabled.";
       input {
         leaf toasterDoneness {
@@ -182,10 +190,10 @@ module toaster {
           }
           default '5';
           description
-            "This variable controls how well-done is the 
+            "This variable controls how well-done is the
                    ensuing toast. It should be on a scale of 1 to 10.
-                   Toast made at 10 generally is considered unfit 
-                   for human consumption; toast made at 1 is warmed 
+                   Toast made at 10 generally is considered unfit
+                   for human consumption; toast made at 1 is warmed
                    lightly.";
         }
 
@@ -195,23 +203,23 @@ module toaster {
           }
           default 'wheat-bread';
           description
-            "This variable informs the toaster of the type of 
-                   material that is being toasted. The toaster 
-                   uses this information, combined with 
-                   toasterDoneness, to compute for how 
-                   long the material must be toasted to achieve 
+            "This variable informs the toaster of the type of
+                   material that is being toasted. The toaster
+                   uses this information, combined with
+                   toasterDoneness, to compute for how
+                   long the material must be toasted to achieve
                    the required doneness.";
         }
       }
-    }  
+    }
 
     rpc cancel-toast {
       description
         "Stop making toast, if any is being made.
-           A 'resource-denied' error will be returned 
+           A 'resource-denied' error will be returned
            if the toaster service is disabled.";
-    }  
-    
+    }
+
     notification toastDone {
       description
         "Indicates that the toast in progress has completed.";
@@ -236,5 +244,5 @@ module toaster {
         description
           "Indicates the final toast status";
       }
-    }  
-  }  
+    }
+  }
index 44227bb4d816042c3aae502a52102da49ce2e534..350b0aa247470e4a430618b8560fe45099ec3987 100644 (file)
@@ -107,7 +107,7 @@ public class InstanceRuntime {
 
                 String elementName = jmxToYangChildRbeMapping.get(childMappingEntry.getKey());
 
-                Element innerXml = XmlUtil.createElement(document, elementName, Optional.<String>absent());
+                Element innerXml = XmlUtil.createElement(document, elementName, Optional.of(namespace));
                 childMappingEntry.getValue().toXml(objectName, innerChildRbeOns, document,
                         runtimeInstanceIndex, innerXml, namespace);
                 xml.appendChild(innerXml);
index e41b174b664740c685faa041d64c208630bf21c2..641881cf9ee50b71119c930a495ded9920575f73 100644 (file)
@@ -662,7 +662,7 @@ public class NetconfMappingTest extends AbstractConfigTest {
         assertEquals(8 * 4, getElementsSize(response, "inner-inner-running-data"));
         assertEquals(8 * 4, getElementsSize(response, "deep3"));
         assertEquals(8 * 4 * 2, getElementsSize(response, "list-of-strings"));
-        assertEquals(8, getElementsSize(response, "inner-running-data-additional"));
+        assertEquals(8, getElementsSize(response, "inner-running-data-additional", "urn:opendaylight:params:xml:ns:yang:controller:test:impl"));
         assertEquals(8, getElementsSize(response, "deep4"));
         // TODO assert keys
 
@@ -693,6 +693,10 @@ public class NetconfMappingTest extends AbstractConfigTest {
         return response.getElementsByTagName(elementName).getLength();
     }
 
+    private int getElementsSize(Document response, String elementName, String namespace) {
+        return response.getElementsByTagNameNS(namespace, elementName).getLength();
+    }
+
     private Document executeOp(final NetconfOperation op, final String filename) throws ParserConfigurationException,
             SAXException, IOException, NetconfDocumentedException {
 
index 6e8158413388d555e9d102354854f684f336d733..42a8bae4484b93a3ed4689223cbf34a9aacbd986 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.controller.netconf.impl;
 
 import com.google.common.base.Optional;
 import java.io.IOException;
+import java.util.Map;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation.OperationNameAndNamespace;
@@ -73,7 +74,7 @@ public class SubtreeFilter {
         return result;
     }
 
-    private static void addSubtree(XmlElement filter, XmlElement src, XmlElement dst) {
+    private static void addSubtree(XmlElement filter, XmlElement src, XmlElement dst) throws NetconfDocumentedException {
         for (XmlElement srcChild : src.getChildElements()) {
             for (XmlElement filterChild : filter.getChildElements()) {
                 addSubtree2(filterChild, srcChild, dst);
@@ -81,7 +82,7 @@ public class SubtreeFilter {
         }
     }
 
-    private static MatchingResult addSubtree2(XmlElement filter, XmlElement src, XmlElement dstParent) {
+    private static MatchingResult addSubtree2(XmlElement filter, XmlElement src, XmlElement dstParent) throws NetconfDocumentedException {
         Document document = dstParent.getDomElement().getOwnerDocument();
         MatchingResult matches = matches(src, filter);
         if (matches != MatchingResult.NO_MATCH && matches != MatchingResult.CONTENT_MISMATCH) {
@@ -123,7 +124,7 @@ public class SubtreeFilter {
      * Shallow compare src node to filter: tag name and namespace must match.
      * If filter node has no children and has text content, it also must match.
      */
-    private static MatchingResult matches(XmlElement src, XmlElement filter) {
+    private static MatchingResult matches(XmlElement src, XmlElement filter) throws NetconfDocumentedException {
         boolean tagMatch = src.getName().equals(filter.getName()) &&
                 src.getNamespaceOptionally().equals(filter.getNamespaceOptionally());
         MatchingResult result = null;
@@ -131,7 +132,7 @@ public class SubtreeFilter {
             // match text content
             Optional<String> maybeText = filter.getOnlyTextContentOptionally();
             if (maybeText.isPresent()) {
-                if (maybeText.equals(src.getOnlyTextContentOptionally())) {
+                if (maybeText.equals(src.getOnlyTextContentOptionally()) || prefixedContentMatches(filter, src)) {
                     result = MatchingResult.CONTENT_MATCH;
                 } else {
                     result = MatchingResult.CONTENT_MISMATCH;
@@ -159,10 +160,30 @@ public class SubtreeFilter {
         if (result == null) {
             result = MatchingResult.NO_MATCH;
         }
-        logger.debug("Matching {} to {} resulted in {}", src, filter, tagMatch);
+        logger.debug("Matching {} to {} resulted in {}", src, filter, result);
         return result;
     }
 
+    private static boolean prefixedContentMatches(final XmlElement filter, final XmlElement src) throws NetconfDocumentedException {
+        final Map.Entry<String, String> prefixToNamespaceOfFilter = filter.findNamespaceOfTextContent();
+        final Map.Entry<String, String> prefixToNamespaceOfSrc = src.findNamespaceOfTextContent();
+
+        final String prefix = prefixToNamespaceOfFilter.getKey();
+        // If this is not a prefixed content, we do not need to continue since content do not match
+        if(prefix.equals(XmlElement.DEFAULT_NAMESPACE_PREFIX)) {
+            return false;
+        }
+        // Namespace mismatch
+        if(!prefixToNamespaceOfFilter.getValue().equals(prefixToNamespaceOfSrc.getValue())) {
+            return false;
+        }
+
+        final String unprefixedFilterContent = filter.getTextContent().substring(prefix.length());
+        final String unprefixedSrcCOntnet = src.getTextContent().substring(prefix.length());
+        // Finally compare unprefixed content
+        return unprefixedFilterContent.equals(unprefixedSrcCOntnet);
+    }
+
     enum MatchingResult {
         NO_MATCH, TAG_MATCH, CONTENT_MATCH, CONTENT_MISMATCH
     }
diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/NetconfMonitoringServiceImplTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/NetconfMonitoringServiceImplTest.java
new file mode 100644 (file)
index 0000000..1b078be
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.impl;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import io.netty.channel.Channel;
+import java.util.List;
+import java.util.Set;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
+import org.opendaylight.controller.netconf.impl.NetconfServerSession;
+import org.opendaylight.controller.netconf.impl.NetconfServerSessionListener;
+import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl;
+import org.opendaylight.controller.netconf.mapping.api.Capability;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceSnapshot;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.*;
+
+public class NetconfMonitoringServiceImplTest {
+
+    private NetconfMonitoringServiceImpl service;
+
+    @Mock
+    private NetconfOperationProvider operationProvider;
+    @Mock
+    private NetconfManagementSession managementSession;
+    @Mock
+    private NetconfOperationServiceSnapshot snapshot;
+    @Mock
+    private NetconfOperationService operationService;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        service = new NetconfMonitoringServiceImpl(operationProvider);
+    }
+
+    @Test
+    public void testSessions() throws Exception {
+        doReturn("sessToStr").when(managementSession).toString();
+        service.onSessionUp(managementSession);
+        List list = Lists.newArrayList(managementSession);
+    }
+
+    @Test(expected = RuntimeException.class)
+    public void testGetSchemas() throws Exception {
+        doThrow(RuntimeException.class).when(operationProvider).openSnapshot(anyString());
+        service.getSchemas();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testGetSchemas2() throws Exception {
+        doThrow(Exception.class).when(operationProvider).openSnapshot(anyString());
+        service.getSchemas();
+    }
+
+    @Test
+    public void testGetSchemas3() throws Exception {
+        doReturn("").when(managementSession).toString();
+        Capability cap = mock(Capability.class);
+        Set caps = Sets.newHashSet(cap);
+        Set services = Sets.newHashSet(operationService);
+        doReturn(snapshot).when(operationProvider).openSnapshot(anyString());
+        doReturn(services).when(snapshot).getServices();
+        doReturn(caps).when(operationService).getCapabilities();
+        Optional opt = mock(Optional.class);
+        doReturn(opt).when(cap).getCapabilitySchema();
+        doReturn(true).when(opt).isPresent();
+        doReturn(opt).when(cap).getModuleNamespace();
+        doReturn("namespace").when(opt).get();
+        Optional optRev = Optional.of("rev");
+        doReturn(optRev).when(cap).getRevision();
+        doReturn(Optional.of("modName")).when(cap).getModuleName();
+        doReturn(Optional.of(Lists.newArrayList("loc"))).when(cap).getLocation();
+        doNothing().when(snapshot).close();
+
+        assertNotNull(service.getSchemas());
+        verify(snapshot, times(1)).close();
+
+        NetconfServerSessionListener sessionListener = mock(NetconfServerSessionListener.class);
+        Channel channel = mock(Channel.class);
+        NetconfHelloMessageAdditionalHeader header = new NetconfHelloMessageAdditionalHeader("name", "addr", "2", "tcp", "id");
+        NetconfServerSession sm = new NetconfServerSession(sessionListener, channel, 10, header);
+        doNothing().when(sessionListener).onSessionUp(any(NetconfServerSession.class));
+        sm.sessionUp();
+        service.onSessionUp(sm);
+        assertEquals(1, service.getSessions().getSession().size());
+
+        assertEquals(Long.valueOf(10), service.getSessions().getSession().get(0).getSessionId());
+
+        service.onSessionDown(sm);
+        assertEquals(0, service.getSessions().getSession().size());
+    }
+}
index b11834386e0f76e761924ee881977cbc5d0b0aef..5d9470750e54053423b8bb871192fafedf9bf53b 100644 (file)
@@ -36,7 +36,7 @@ public class SubtreeFilterTest {
     @Parameters
     public static Collection<Object[]> data() {
         List<Object[]> result = new ArrayList<>();
-        for (int i = 0; i <= 8; i++) {
+        for (int i = 0; i <= 9; i++) {
             result.add(new Object[]{i});
         }
         return result;
diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultCloseSessionTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultCloseSessionTest.java
new file mode 100644 (file)
index 0000000..ae3d656
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.impl.mapping.operations;
+
+import org.junit.Test;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+
+public class DefaultCloseSessionTest {
+    @Test
+    public void testDefaultCloseSession() throws Exception {
+        AutoCloseable res = mock(AutoCloseable.class);
+        doNothing().when(res).close();
+        DefaultCloseSession session = new DefaultCloseSession("", res);
+        Document doc = XmlUtil.newDocument();
+        XmlElement elem = XmlElement.fromDomElement(XmlUtil.readXmlToElement("<elem/>"));
+        session.handleWithNoSubsequentOperations(doc, elem);
+    }
+
+    @Test(expected = NetconfDocumentedException.class)
+    public void testDefaultCloseSession2() throws Exception {
+        AutoCloseable res = mock(AutoCloseable.class);
+        doThrow(NetconfDocumentedException.class).when(res).close();
+        DefaultCloseSession session = new DefaultCloseSession("", res);
+        Document doc = XmlUtil.newDocument();
+        XmlElement elem = XmlElement.fromDomElement(XmlUtil.readXmlToElement("<elem/>"));
+        session.handleWithNoSubsequentOperations(doc, elem);
+    }
+}
diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultCommitTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultCommitTest.java
new file mode 100644 (file)
index 0000000..98050de
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.impl.mapping.operations;
+
+import com.google.common.collect.Sets;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
+import org.opendaylight.controller.netconf.impl.NetconfServerSession;
+import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
+import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouter;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
+import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import static org.mockito.Mockito.*;
+
+public class DefaultCommitTest {
+
+    private NetconfOperationChainedExecution operation;
+    private Document requestMessage;
+    private NetconfOperationRouter router;
+    private DefaultCommitNotificationProducer notifier;
+    private CapabilityProvider cap;
+    private DefaultCommit commit;
+
+    @Before
+    public void setUp() throws Exception {
+        operation = mock(NetconfOperationChainedExecution.class);
+        doReturn(XmlUtil.newDocument()).when(operation).execute(any(Document.class));
+        router = mock(NetconfOperationRouter.class);
+        doReturn(false).when(operation).isExecutionTermination();
+        notifier = mock(DefaultCommitNotificationProducer.class);
+        doNothing().when(notifier).sendCommitNotification(anyString(), any(Element.class), anySetOf(String.class));
+        cap = mock(CapabilityProvider.class);
+        doReturn(Sets.newHashSet()).when(cap).getCapabilities();
+        Document rpcData = XmlFileLoader.xmlFileToDocument("netconfMessages/editConfig_expectedResult.xml");
+        doReturn(rpcData).when(router).onNetconfMessage(any(Document.class), any(NetconfServerSession.class));
+        commit = new DefaultCommit(notifier, cap, "", router);
+    }
+
+    @Test
+    public void testHandleWithNotification() throws Exception {
+        requestMessage = XmlFileLoader.xmlFileToDocument("netconfMessages/commit.xml");
+        commit.handle(requestMessage, operation);
+        verify(operation, times(1)).execute(requestMessage);
+        verify(notifier, times(1)).sendCommitNotification(anyString(), any(Element.class), anySetOf(String.class));
+    }
+
+    @Test
+    public void testHandleWithoutNotification() throws Exception {
+        requestMessage = XmlFileLoader.xmlFileToDocument("netconfMessages/commit.xml");
+        Element elem = requestMessage.getDocumentElement();
+        elem.setAttribute("notify", "false");
+        commit.handle(requestMessage, operation);
+        verify(operation, times(1)).execute(requestMessage);
+        verify(notifier, never()).sendCommitNotification(anyString(), any(Element.class), anySetOf(String.class));
+    }
+
+    @Test(expected = NetconfDocumentedException.class)
+    public void testHandle() throws Exception {
+        Document rpcData = XmlFileLoader.xmlFileToDocument("netconfMessages/get.xml");
+        doReturn(rpcData).when(router).onNetconfMessage(any(Document.class), any(NetconfServerSession.class));
+        requestMessage = XmlFileLoader.xmlFileToDocument("netconfMessages/commit.xml");
+        commit.handle(requestMessage, operation);
+    }
+}
diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultGetSchemaTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultGetSchemaTest.java
new file mode 100644 (file)
index 0000000..b655e90
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.impl.mapping.operations;
+
+import com.google.common.base.Optional;
+import junit.framework.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.w3c.dom.Document;
+
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+
+public class DefaultGetSchemaTest {
+
+    private CapabilityProvider cap;
+    private Document doc;
+    private String getSchema;
+
+    @Before
+    public void setUp() throws Exception {
+        cap = mock(CapabilityProvider.class);
+        doc = XmlUtil.newDocument();
+        getSchema = "<get-schema xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\">\n" +
+                "        <identifier>threadpool-api</identifier>\n" +
+                "        <version>2010-09-24</version>\n" +
+                "        <format\n" +
+                "                xmlns:ncm=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\">ncm:yang\n" +
+                "        </format>\n" +
+                "    </get-schema>";
+    }
+
+    @Test(expected = NetconfDocumentedException.class)
+    public void testDefaultGetSchema() throws Exception {
+        DefaultGetSchema schema = new DefaultGetSchema(cap, "");
+        doThrow(IllegalStateException.class).when(cap).getSchemaForCapability(anyString(), any(Optional.class));
+        schema.handleWithNoSubsequentOperations(doc, XmlElement.fromDomElement(XmlUtil.readXmlToElement(getSchema)));
+    }
+
+    @Test
+    public void handleWithNoSubsequentOperations() throws Exception {
+        DefaultGetSchema schema = new DefaultGetSchema(cap, "");
+        doReturn("").when(cap).getSchemaForCapability(anyString(), any(Optional.class));
+        assertNotNull(schema.handleWithNoSubsequentOperations(doc, XmlElement.fromDomElement(XmlUtil.readXmlToElement(getSchema))));
+    }
+}
diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultStopExiTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultStopExiTest.java
new file mode 100644 (file)
index 0000000..b335165
--- /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.netconf.impl.mapping.operations;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelPipeline;
+import org.junit.Test;
+import org.opendaylight.controller.netconf.impl.NetconfServerSession;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.w3c.dom.Document;
+
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.*;
+
+public class DefaultStopExiTest {
+    @Test
+    public void testHandleWithNoSubsequentOperations() throws Exception {
+        DefaultStopExi exi = new DefaultStopExi("");
+        Document doc = XmlUtil.newDocument();
+        Channel channel = mock(Channel.class);
+        ChannelPipeline pipeline = mock(ChannelPipeline.class);
+        doReturn(pipeline).when(channel).pipeline();
+        ChannelHandler channelHandler = mock(ChannelHandler.class);
+        doReturn(channelHandler).when(pipeline).replace(anyString(), anyString(), any(ChannelHandler.class));
+
+        NetconfServerSession serverSession = new NetconfServerSession(null, channel, 2L, null);
+        exi.setNetconfSession(serverSession);
+
+        assertNotNull(exi.handleWithNoSubsequentOperations(doc, XmlElement.fromDomElement(XmlUtil.readXmlToElement("<elem/>"))));
+        verify(pipeline, times(1)).replace(anyString(), anyString(), any(ChannelHandler.class));
+    }
+}
diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/osgi/NetconfImplActivatorTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/osgi/NetconfImplActivatorTest.java
new file mode 100644 (file)
index 0000000..b59ea88
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.impl.osgi;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Dictionary;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
+import org.osgi.framework.*;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.*;
+
+public class NetconfImplActivatorTest {
+
+    @Mock
+    private BundleContext bundle;
+    @Mock
+    private Filter filter;
+    @Mock
+    private ServiceReference reference;
+    @Mock
+    private ServiceRegistration registration;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        doReturn(filter).when(bundle).createFilter(anyString());
+        doNothing().when(bundle).addServiceListener(any(ServiceListener.class), anyString());
+
+        ServiceReference[] refs = new ServiceReference[0];
+        doReturn(refs).when(bundle).getServiceReferences(anyString(), anyString());
+        doReturn(Arrays.asList(refs)).when(bundle).getServiceReferences(any(Class.class), anyString());
+        doReturn("").when(bundle).getProperty(anyString());
+        doReturn(registration).when(bundle).registerService(any(Class.class), any(NetconfOperationServiceFactoryListenerImpl.class), any(Dictionary.class));
+        doNothing().when(registration).unregister();
+        doNothing().when(bundle).removeServiceListener(any(ServiceListener.class));
+    }
+
+    @Test
+    public void testStart() throws Exception {
+        NetconfImplActivator activator = new NetconfImplActivator();
+        activator.start(bundle);
+        verify(bundle, times(2)).registerService(any(Class.class), any(NetconfOperationServiceFactoryListenerImpl.class), any(Dictionary.class));
+        activator.stop(bundle);
+    }
+}
diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationServiceFactoryTrackerTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationServiceFactoryTrackerTest.java
new file mode 100644 (file)
index 0000000..374e8ae
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.impl.osgi;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceReference;
+
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.*;
+
+public class NetconfOperationServiceFactoryTrackerTest {
+
+    @Mock
+    private Filter filter;
+    @Mock
+    private BundleContext context;
+    @Mock
+    private NetconfOperationServiceFactoryListener listener;
+    @Mock
+    private NetconfOperationServiceFactory factory;
+    @Mock
+    private ServiceReference reference;
+
+    private NetconfOperationServiceFactoryTracker tracker;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        doNothing().when(listener).onRemoveNetconfOperationServiceFactory(any(NetconfOperationServiceFactory.class));
+        doReturn(filter).when(context).createFilter(anyString());
+        doReturn("").when(reference).toString();
+        doReturn(factory).when(context).getService(any(ServiceReference.class));
+        doReturn("").when(factory).toString();
+        doNothing().when(listener).onAddNetconfOperationServiceFactory(any(NetconfOperationServiceFactory.class));
+        tracker = new NetconfOperationServiceFactoryTracker(context, listener);
+    }
+
+    @Test
+    public void testNetconfOperationServiceFactoryTracker() throws Exception {
+        tracker.removedService(null, factory);
+        verify(listener, times(1)).onRemoveNetconfOperationServiceFactory(any(NetconfOperationServiceFactory.class));
+    }
+
+    @Test
+    public void testAddingService() throws Exception {
+        assertNotNull(tracker.addingService(reference));
+        verify(listener, times(1)).onAddNetconfOperationServiceFactory(any(NetconfOperationServiceFactory.class));
+    }
+}
diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/util/DeserializerExceptionHandlerTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/util/DeserializerExceptionHandlerTest.java
new file mode 100644 (file)
index 0000000..6512b4b
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.impl.util;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.util.concurrent.GenericFutureListener;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.mockito.Mockito.*;
+
+public class DeserializerExceptionHandlerTest {
+
+    private DeserializerExceptionHandler handler;
+    private ChannelFuture channelFuture;
+    private ChannelHandlerContext context;
+    private Channel channel;
+
+    @Before
+    public void setUp() throws Exception {
+        handler = new DeserializerExceptionHandler();
+        context = mock(ChannelHandlerContext.class);
+        channel = mock(Channel.class);
+        doReturn(channel).when(context).channel();
+        channelFuture = mock(ChannelFuture.class);
+        doReturn(channelFuture).when(channelFuture).addListener(any(GenericFutureListener.class));
+        doReturn(channelFuture).when(channel).writeAndFlush(anyObject());
+    }
+
+    @Test
+    public void testExceptionCaught() throws Exception {
+        handler.exceptionCaught(context, new Exception());
+        verify(context, times(1)).channel();
+    }
+}
diff --git a/opendaylight/netconf/netconf-impl/src/test/resources/subtree/9/post-filter.xml b/opendaylight/netconf/netconf-impl/src/test/resources/subtree/9/post-filter.xml
new file mode 100644 (file)
index 0000000..afe9655
--- /dev/null
@@ -0,0 +1,14 @@
+<rpc-reply message-id="5"
+           xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+  <data>
+    <top xmlns="http://example.com/schema/1.2/config">
+      <users>
+        <user>
+          <name>fred</name>
+            <type xmlns:x="http://java.sun.com/dtd/properties.dtd">x:admin</type>
+          <full-name>Fred Flintstone</full-name>
+        </user>
+      </users>
+    </top>
+  </data>
+</rpc-reply>
\ No newline at end of file
diff --git a/opendaylight/netconf/netconf-impl/src/test/resources/subtree/9/pre-filter.xml b/opendaylight/netconf/netconf-impl/src/test/resources/subtree/9/pre-filter.xml
new file mode 100644 (file)
index 0000000..eca3241
--- /dev/null
@@ -0,0 +1,40 @@
+<rpc-reply message-id="5" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+  <data>
+    <top xmlns="http://example.com/schema/1.2/config">
+      <users>
+        <user>
+          <name>root</name>
+          <type>superuser</type>
+          <full-name>Charlie Root</full-name>
+          <company-info>
+            <dept>1</dept>
+            <id>1</id>
+          </company-info>
+        </user>
+        <user>
+          <name>fred</name>
+          <type xmlns:x="http://java.sun.com/dtd/properties.dtd">x:admin</type>
+          <full-name>Fred Flintstone</full-name>
+          <company-info>
+            <dept>2</dept>
+            <id>2</id>
+          </company-info>
+        </user>
+        <user>
+          <name>barney</name>
+          <type>admin</type>
+          <full-name>Barney Rubble</full-name>
+          <company-info>
+            <dept>2</dept>
+            <id>3</id>
+          </company-info>
+        </user>
+      </users>
+      <groups>
+        <group>
+          <name>admin</name>
+        </group>
+      </groups>
+    </top>
+  </data>
+</rpc-reply>
\ No newline at end of file
diff --git a/opendaylight/netconf/netconf-impl/src/test/resources/subtree/9/request.xml b/opendaylight/netconf/netconf-impl/src/test/resources/subtree/9/request.xml
new file mode 100644 (file)
index 0000000..47da0fe
--- /dev/null
@@ -0,0 +1,19 @@
+<rpc message-id="5"
+     xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+  <get-config>
+    <source>
+      <running/>
+    </source>
+    <filter type="subtree">
+      <top xmlns="http://example.com/schema/1.2/config">
+        <users>
+          <user>
+            <name>fred</name>
+              <type xmlns:a="http://java.sun.com/dtd/properties.dtd">a:admin</type>
+            <full-name/>
+          </user>
+        </users>
+      </top>
+    </filter>
+  </get-config>
+</rpc>
\ No newline at end of file
index 1adcd7e49176e65cc15c5fb558015e5e6e129205..f96f55761939bdd5e7eb05eca5a6b8b645572208 100644 (file)
@@ -21,14 +21,23 @@ import com.google.common.collect.Lists;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
+import io.netty.channel.EventLoopGroup;
 import io.netty.channel.local.LocalAddress;
+import io.netty.channel.nio.NioEventLoopGroup;
 import io.netty.util.concurrent.GlobalEventExecutor;
 import java.io.IOException;
 import java.net.InetSocketAddress;
+import java.nio.file.Files;
 import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.sshd.server.PasswordAuthenticator;
+import org.apache.sshd.server.keyprovider.PEMGeneratorHostKeyProvider;
+import org.apache.sshd.server.session.ServerSession;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -40,13 +49,12 @@ import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
 import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
 import org.opendaylight.controller.netconf.client.NetconfClientSessionListener;
 import org.opendaylight.controller.netconf.client.SimpleNetconfClientSessionListener;
+import org.opendaylight.controller.netconf.client.TestingNetconfClient;
 import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
 import org.opendaylight.controller.netconf.client.conf.NetconfClientConfigurationBuilder;
-import org.opendaylight.controller.netconf.client.TestingNetconfClient;
 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.ssh.SshProxyServer;
 import org.opendaylight.controller.netconf.util.messages.NetconfMessageUtil;
 import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
@@ -68,19 +76,32 @@ public class NetconfITSecureTest extends AbstractNetconfConfigTest {
     public static final String USERNAME = "user";
     public static final String PASSWORD = "pwd";
 
-    private NetconfSSHServer sshServer;
+    private SshProxyServer sshProxyServer;
+
+    private ExecutorService nioExec;
+    private EventLoopGroup clientGroup;
+    private ScheduledExecutorService minaTimerEx;
 
     @Before
     public void setUp() throws Exception {
-        final char[] pem = PEMGenerator.generate().toCharArray();
-        sshServer = NetconfSSHServer.start(TLS_ADDRESS.getPort(), NetconfConfigUtil.getNetconfLocalAddress(), getNettyThreadgroup(), pem);
-        sshServer.setAuthProvider(getAuthProvider());
+        nioExec = Executors.newFixedThreadPool(1);
+        clientGroup = new NioEventLoopGroup();
+        minaTimerEx = Executors.newScheduledThreadPool(1);
+        sshProxyServer = new SshProxyServer(minaTimerEx, clientGroup, nioExec);
+        sshProxyServer.bind(TLS_ADDRESS, NetconfConfigUtil.getNetconfLocalAddress(), new PasswordAuthenticator() {
+            @Override
+            public boolean authenticate(final String username, final String password, final ServerSession session) {
+                return true;
+            }
+        }, new PEMGeneratorHostKeyProvider(Files.createTempFile("prefix", "suffix").toAbsolutePath().toString()));
     }
 
     @After
     public void tearDown() throws Exception {
-        sshServer.close();
-        sshServer.join();
+        sshProxyServer.close();
+        clientGroup.shutdownGracefully().await();
+        minaTimerEx.shutdownNow();
+        nioExec.shutdownNow();
     }
 
     @Test
diff --git a/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringActivatorTest.java b/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringActivatorTest.java
new file mode 100644 (file)
index 0000000..4049356
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.monitoring.osgi;
+
+import java.util.Arrays;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.*;
+
+public class NetconfMonitoringActivatorTest {
+
+    @Mock
+    BundleContext context;
+    @Mock
+    Filter filter;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        doReturn(filter).when(context).createFilter(anyString());
+        doNothing().when(context).addServiceListener(any(ServiceListener.class), anyString());
+        ServiceReference[] refs = new ServiceReference[2];
+        doReturn(Arrays.asList(refs)).when(context).getServiceReferences(any(Class.class), anyString());
+        doReturn(refs).when(context).getServiceReferences(anyString(), anyString());
+    }
+
+    @Test
+    public void testNetconfMonitoringActivator() throws Exception {
+        NetconfMonitoringActivator activator = new NetconfMonitoringActivator();
+        activator.start(context);
+        verify(context, times(1)).addServiceListener(any(ServiceListener.class), anyString());
+
+        activator.stop(context);
+        verify(context, times(1)).removeServiceListener(any(ServiceListener.class));
+    }
+}
diff --git a/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringOperationServiceTest.java b/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringOperationServiceTest.java
new file mode 100644 (file)
index 0000000..b8e35e9
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.monitoring.osgi;
+
+import com.google.common.base.Optional;
+import org.junit.Test;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
+import org.opendaylight.controller.netconf.monitoring.MonitoringConstants;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+
+public class NetconfMonitoringOperationServiceTest {
+    @Test
+    public void testGetters() throws Exception {
+        NetconfMonitoringService monitor = mock(NetconfMonitoringService.class);
+        NetconfMonitoringOperationService service = new NetconfMonitoringOperationService(monitor);
+
+        assertEquals(1, service.getNetconfOperations().size());
+
+        assertEquals(Optional.absent(), service.getCapabilities().iterator().next().getCapabilitySchema());
+        assertEquals(Optional.absent(), service.getCapabilities().iterator().next().getLocation());
+        assertEquals(Optional.of(MonitoringConstants.MODULE_REVISION), service.getCapabilities().iterator().next().getRevision());
+        assertEquals(Optional.of(MonitoringConstants.MODULE_NAME), service.getCapabilities().iterator().next().getModuleName());
+        assertEquals(Optional.of(MonitoringConstants.NAMESPACE), service.getCapabilities().iterator().next().getModuleNamespace());
+        assertEquals(MonitoringConstants.URI, service.getCapabilities().iterator().next().getCapabilityUri());
+    }
+}
diff --git a/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringServiceTrackerTest.java b/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringServiceTrackerTest.java
new file mode 100644 (file)
index 0000000..2a53a6c
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.monitoring.osgi;
+
+import java.util.Hashtable;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyCollection;
+import static org.mockito.Mockito.*;
+
+public class NetconfMonitoringServiceTrackerTest {
+
+    @Mock
+    private ServiceReference reference;
+    @Mock
+    private BundleContext context;
+    @Mock
+    private ServiceRegistration serviceRegistration;
+    @Mock
+    private Filter filter;
+    @Mock
+    private NetconfMonitoringService monitoringService;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        doReturn(serviceRegistration).when(context).registerService(any(Class.class), any(NetconfOperationServiceFactory.class), any(Hashtable.class));
+        doNothing().when(serviceRegistration).unregister();
+        doReturn(filter).when(context).createFilter(anyString());
+        doReturn("").when(reference).toString();
+        doReturn(monitoringService).when(context).getService(any(ServiceReference.class));
+    }
+
+    @Test
+    public void testAddingService() throws Exception {
+        NetconfMonitoringServiceTracker tracker = new NetconfMonitoringServiceTracker(context);
+        tracker.addingService(reference);
+        verify(context, times(1)).registerService(any(Class.class), any(NetconfOperationServiceFactory.class), any(Hashtable.class));
+        tracker.removedService(reference, null);
+        verify(serviceRegistration, times(1)).unregister();
+    }
+}
index 3bd72320232bb7f912a316469b816fa76952f0c4..fa7d0900edc805ebd45f3b2edce8a21d46cfb031 100644 (file)
@@ -8,12 +8,9 @@
 
 package org.opendaylight.controller.netconf.nettyutil.handler.ssh.client;
 
-import com.google.common.base.Preconditions;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.ChannelOutboundHandlerAdapter;
-import io.netty.channel.ChannelPromise;
 import java.io.IOException;
 import java.net.SocketAddress;
+
 import org.apache.sshd.ClientChannel;
 import org.apache.sshd.ClientSession;
 import org.apache.sshd.SshClient;
@@ -26,6 +23,13 @@ import org.opendaylight.controller.netconf.nettyutil.handler.ssh.authentication.
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Preconditions;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelOutboundHandlerAdapter;
+import io.netty.channel.ChannelPromise;
+
 /**
  * Netty SSH handler class. Acts as interface between Netty and SSH library.
  */
@@ -47,7 +51,7 @@ public class AsyncSshHandler extends ChannelOutboundHandlerAdapter {
     private final AuthenticationHandler authenticationHandler;
     private final SshClient sshClient;
 
-    private AsyncSshHanderReader sshReadAsyncListener;
+    private AsyncSshHandlerReader sshReadAsyncListener;
     private AsyncSshHandlerWriter sshWriteAsyncHandler;
 
     private ClientChannel channel;
@@ -138,7 +142,20 @@ public class AsyncSshHandler extends ChannelOutboundHandlerAdapter {
         connectPromise.setSuccess();
         connectPromise = null;
 
-        sshReadAsyncListener = new AsyncSshHanderReader(this, ctx, channel.getAsyncOut());
+        // TODO we should also read from error stream and at least log from that
+
+        sshReadAsyncListener = new AsyncSshHandlerReader(new AutoCloseable() {
+            @Override
+            public void close() throws Exception {
+                AsyncSshHandler.this.disconnect(ctx, ctx.newPromise());
+            }
+        }, new AsyncSshHandlerReader.ReadMsgHandler() {
+            @Override
+            public void onMessageRead(final ByteBuf msg) {
+                ctx.fireChannelRead(msg);
+            }
+        }, channel.toString(), channel.getAsyncOut());
+
         // if readAsyncListener receives immediate close, it will close this handler and closing this handler sets channel variable to null
         if(channel != null) {
             sshWriteAsyncHandler = new AsyncSshHandlerWriter(channel.getAsyncIn());
@@ -8,9 +8,8 @@
 
 package org.opendaylight.controller.netconf.nettyutil.handler.ssh.client;
 
+import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.ChannelOutboundHandler;
 import org.apache.sshd.common.future.SshFutureListener;
 import org.apache.sshd.common.io.IoInputStream;
 import org.apache.sshd.common.io.IoReadFuture;
@@ -22,22 +21,24 @@ import org.slf4j.LoggerFactory;
  * Listener on async input stream from SSH session.
  * This listeners schedules reads in a loop until the session is closed or read fails.
  */
-final class AsyncSshHanderReader implements SshFutureListener<IoReadFuture>, AutoCloseable {
+public final class AsyncSshHandlerReader implements SshFutureListener<IoReadFuture>, AutoCloseable {
 
     private static final Logger logger = LoggerFactory.getLogger(AsyncSshHandler.class);
 
     private static final int BUFFER_SIZE = 8192;
 
-    private final ChannelOutboundHandler asyncSshHandler;
-    private final ChannelHandlerContext ctx;
+    private final AutoCloseable connectionClosedCallback;
+    private final ReadMsgHandler readHandler;
 
+    private final String channelId;
     private IoInputStream asyncOut;
     private Buffer buf;
     private IoReadFuture currentReadFuture;
 
-    public AsyncSshHanderReader(final ChannelOutboundHandler asyncSshHandler, final ChannelHandlerContext ctx, final IoInputStream asyncOut) {
-        this.asyncSshHandler = asyncSshHandler;
-        this.ctx = ctx;
+    public AsyncSshHandlerReader(final AutoCloseable connectionClosedCallback, final ReadMsgHandler readHandler, final String channelId, final IoInputStream asyncOut) {
+        this.connectionClosedCallback = connectionClosedCallback;
+        this.readHandler = readHandler;
+        this.channelId = channelId;
         this.asyncOut = asyncOut;
         buf = new Buffer(BUFFER_SIZE);
         asyncOut.read(buf).addListener(this);
@@ -48,16 +49,20 @@ final class AsyncSshHanderReader implements SshFutureListener<IoReadFuture>, Aut
         if(future.getException() != null) {
             if(asyncOut.isClosed() || asyncOut.isClosing()) {
                 // Ssh dropped
-                logger.debug("Ssh session dropped on channel: {}", ctx.channel(), future.getException());
+                logger.debug("Ssh session dropped on channel: {}", channelId, future.getException());
             } else {
-                logger.warn("Exception while reading from SSH remote on channel {}", ctx.channel(), future.getException());
+                logger.warn("Exception while reading from SSH remote on channel {}", channelId, future.getException());
             }
             invokeDisconnect();
             return;
         }
 
         if (future.getRead() > 0) {
-            ctx.fireChannelRead(Unpooled.wrappedBuffer(buf.array(), 0, future.getRead()));
+            final ByteBuf msg = Unpooled.wrappedBuffer(buf.array(), 0, future.getRead());
+            if(logger.isTraceEnabled()) {
+                logger.trace("Reading message on channel: {}, message: {}", channelId, AsyncSshHandlerWriter.byteBufToString(msg));
+            }
+            readHandler.onMessageRead(msg);
 
             // Schedule next read
             buf = new Buffer(BUFFER_SIZE);
@@ -68,7 +73,7 @@ final class AsyncSshHanderReader implements SshFutureListener<IoReadFuture>, Aut
 
     private void invokeDisconnect() {
         try {
-            asyncSshHandler.disconnect(ctx, ctx.newPromise());
+            connectionClosedCallback.close();
         } catch (final Exception e) {
             // This should not happen
             throw new IllegalStateException(e);
@@ -80,8 +85,14 @@ final class AsyncSshHanderReader implements SshFutureListener<IoReadFuture>, Aut
         // Remove self as listener on close to prevent reading from closed input
         if(currentReadFuture != null) {
             currentReadFuture.removeListener(this);
+            currentReadFuture = null;
         }
 
         asyncOut = null;
     }
+
+    public interface ReadMsgHandler {
+
+        void onMessageRead(ByteBuf msg);
+    }
 }
index eace0ac7eafe1d09381fbe597f9f6acfece953e6..8e639bd47cc1b24e18176e365d50df2d3185ae5c 100644 (file)
@@ -28,7 +28,7 @@ import org.slf4j.LoggerFactory;
  * Async Ssh writer. Takes messages(byte arrays) and sends them encrypted to remote server.
  * Also handles pending writes by caching requests until pending state is over.
  */
-final class AsyncSshHandlerWriter implements AutoCloseable {
+public final class AsyncSshHandlerWriter implements AutoCloseable {
 
     private static final Logger logger = LoggerFactory
             .getLogger(AsyncSshHandlerWriter.class);
@@ -116,7 +116,7 @@ final class AsyncSshHandlerWriter implements AutoCloseable {
         writeWithPendingDetection(pendingWrite.ctx, pendingWrite.promise, msg);
     }
 
-    private static String byteBufToString(final ByteBuf msg) {
+    public static String byteBufToString(final ByteBuf msg) {
         msg.resetReaderIndex();
         final String s = msg.toString(Charsets.UTF_8);
         msg.resetReaderIndex();
index d0fc43d04aa2ce656f7616072522437009e92342..212eabb290656cb676c6cf6f925ee132f2b43242 100644 (file)
@@ -459,6 +459,8 @@ public class AsyncSshHandlerTest {
 
     private ChannelSubsystem getMockedSubsystemChannel(final IoInputStream asyncOut, final IoOutputStream asyncIn) throws IOException {
         final ChannelSubsystem subsystemChannel = mock(ChannelSubsystem.class);
+        doReturn("subsystemChannel").when(subsystemChannel).toString();
+
         doNothing().when(subsystemChannel).setStreaming(any(ClientChannel.Streaming.class));
         final OpenFuture openFuture = mock(OpenFuture.class);
 
index 221626b7410a4fa166dbcb63616d93dff2994abd..78453b177037d88b91945e8138bf0bdcd541d8b9 100644 (file)
@@ -60,7 +60,6 @@
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>netconf-netty-util</artifactId>
-      <scope>test</scope>
     </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/RemoteNetconfCommand.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/RemoteNetconfCommand.java
new file mode 100644 (file)
index 0000000..e642e07
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.ssh;
+
+import com.google.common.base.Preconditions;
+import io.netty.bootstrap.Bootstrap;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.local.LocalAddress;
+import io.netty.channel.local.LocalChannel;
+import io.netty.util.concurrent.GenericFutureListener;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.io.IoInputStream;
+import org.apache.sshd.common.io.IoOutputStream;
+import org.apache.sshd.server.AsyncCommand;
+import org.apache.sshd.server.Command;
+import org.apache.sshd.server.Environment;
+import org.apache.sshd.server.ExitCallback;
+import org.apache.sshd.server.SessionAware;
+import org.apache.sshd.server.session.ServerSession;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This command handles all netconf related rpc and forwards to delegate server.
+ * Uses netty to make a local connection to delegate server.
+ *
+ * Command is Apache Mina SSH terminology for objects handling ssh data.
+ */
+public class RemoteNetconfCommand implements AsyncCommand, SessionAware {
+
+    private static final Logger logger = LoggerFactory.getLogger(RemoteNetconfCommand.class);
+
+    private final EventLoopGroup clientEventGroup;
+    private final LocalAddress localAddress;
+
+    private IoInputStream in;
+    private IoOutputStream out;
+    private ExitCallback callback;
+    private NetconfHelloMessageAdditionalHeader netconfHelloMessageAdditionalHeader;
+
+    private Channel clientChannel;
+    private ChannelFuture clientChannelFuture;
+
+    public RemoteNetconfCommand(final EventLoopGroup clientEventGroup, final LocalAddress localAddress) {
+        this.clientEventGroup = clientEventGroup;
+        this.localAddress = localAddress;
+    }
+
+    @Override
+    public void setIoInputStream(final IoInputStream in) {
+        this.in = in;
+    }
+
+    @Override
+    public void setIoOutputStream(final IoOutputStream out) {
+        this.out = out;
+    }
+
+    @Override
+    public void setIoErrorStream(final IoOutputStream err) {
+        // TODO do we want to use error stream in some way ?
+    }
+
+    @Override
+    public void setInputStream(final InputStream in) {
+        throw new UnsupportedOperationException("Synchronous IO is unsupported");
+    }
+
+    @Override
+    public void setOutputStream(final OutputStream out) {
+        throw new UnsupportedOperationException("Synchronous IO is unsupported");
+
+    }
+
+    @Override
+    public void setErrorStream(final OutputStream err) {
+        throw new UnsupportedOperationException("Synchronous IO is unsupported");
+
+    }
+
+    @Override
+    public void setExitCallback(final ExitCallback callback) {
+        this.callback = callback;
+    }
+
+    @Override
+    public void start(final Environment env) throws IOException {
+        logger.trace("Establishing internal connection to netconf server for client: {}", getClientAddress());
+
+        final Bootstrap clientBootstrap = new Bootstrap();
+        clientBootstrap.group(clientEventGroup).channel(LocalChannel.class);
+
+        clientBootstrap
+                .handler(new ChannelInitializer<LocalChannel>() {
+                    @Override
+                    public void initChannel(final LocalChannel ch) throws Exception {
+                        ch.pipeline().addLast(new SshProxyClientHandler(in, out, netconfHelloMessageAdditionalHeader, callback));
+                    }
+                });
+        clientChannelFuture = clientBootstrap.connect(localAddress);
+        clientChannelFuture.addListener(new GenericFutureListener<ChannelFuture>() {
+
+            @Override
+            public void operationComplete(final ChannelFuture future) throws Exception {
+                if(future.isSuccess()) {
+                    clientChannel = clientChannelFuture.channel();
+                } else {
+                    logger.warn("Unable to establish internal connection to netconf server for client: {}", getClientAddress());
+                    Preconditions.checkNotNull(callback, "Exit callback must be set");
+                    callback.onExit(1, "Unable to establish internal connection to netconf server for client: "+ getClientAddress());
+                }
+            }
+        });
+    }
+
+    @Override
+    public void destroy() {
+        logger.trace("Releasing internal connection to netconf server for client: {} on channel: {}",
+                getClientAddress(), clientChannel);
+
+        clientChannelFuture.cancel(true);
+        if(clientChannel != null) {
+            clientChannel.close().addListener(new GenericFutureListener<ChannelFuture>() {
+
+                @Override
+                public void operationComplete(final ChannelFuture future) throws Exception {
+                    if (future.isSuccess() == false) {
+                        logger.warn("Unable to release internal connection to netconf server on channel: {}", clientChannel);
+                    }
+                }
+            });
+        }
+    }
+
+    private String getClientAddress() {
+        return netconfHelloMessageAdditionalHeader.getAddress();
+    }
+
+    @Override
+    public void setSession(final ServerSession session) {
+        final SocketAddress remoteAddress = session.getIoSession().getRemoteAddress();
+        String hostName = "";
+        String port = "";
+        if(remoteAddress instanceof InetSocketAddress) {
+            hostName = ((InetSocketAddress) remoteAddress).getAddress().getHostAddress();
+            port = Integer.toString(((InetSocketAddress) remoteAddress).getPort());
+        }
+        netconfHelloMessageAdditionalHeader = new NetconfHelloMessageAdditionalHeader(
+                session.getUsername(), hostName, port, "ssh", "client");
+    }
+
+    public static class NetconfCommandFactory implements NamedFactory<Command> {
+
+        public static final String NETCONF = "netconf";
+
+        private final EventLoopGroup clientBootstrap;
+        private final LocalAddress localAddress;
+
+        public NetconfCommandFactory(final EventLoopGroup clientBootstrap, final LocalAddress localAddress) {
+
+            this.clientBootstrap = clientBootstrap;
+            this.localAddress = localAddress;
+        }
+
+        @Override
+        public String getName() {
+            return NETCONF;
+        }
+
+        @Override
+        public RemoteNetconfCommand create() {
+            return new RemoteNetconfCommand(clientBootstrap, localAddress);
+        }
+    }
+
+}
diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SshProxyClientHandler.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SshProxyClientHandler.java
new file mode 100644 (file)
index 0000000..2b2b3b3
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.ssh;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import org.apache.sshd.common.io.IoInputStream;
+import org.apache.sshd.common.io.IoOutputStream;
+import org.apache.sshd.server.ExitCallback;
+import org.opendaylight.controller.netconf.nettyutil.handler.ssh.client.AsyncSshHandlerReader;
+import org.opendaylight.controller.netconf.nettyutil.handler.ssh.client.AsyncSshHandlerWriter;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Netty handler that reads SSH from remote client and writes to delegate server and reads from delegate server and writes to remote client
+ */
+final class SshProxyClientHandler extends ChannelInboundHandlerAdapter {
+
+    private static final Logger logger = LoggerFactory.getLogger(SshProxyClientHandler.class);
+
+    private final IoInputStream in;
+    private final IoOutputStream out;
+
+    private AsyncSshHandlerReader asyncSshHandlerReader;
+    private AsyncSshHandlerWriter asyncSshHandlerWriter;
+
+    private final NetconfHelloMessageAdditionalHeader netconfHelloMessageAdditionalHeader;
+    private final ExitCallback callback;
+
+    public SshProxyClientHandler(final IoInputStream in, final IoOutputStream out,
+                                 final NetconfHelloMessageAdditionalHeader netconfHelloMessageAdditionalHeader,
+                                 final ExitCallback callback) {
+        this.in = in;
+        this.out = out;
+        this.netconfHelloMessageAdditionalHeader = netconfHelloMessageAdditionalHeader;
+        this.callback = callback;
+    }
+
+    @Override
+    public void channelActive(final ChannelHandlerContext ctx) throws Exception {
+        writeAdditionalHeader(ctx);
+
+        asyncSshHandlerWriter = new AsyncSshHandlerWriter(out);
+        asyncSshHandlerReader = new AsyncSshHandlerReader(new AutoCloseable() {
+            @Override
+            public void close() throws Exception {
+                // Close both sessions (delegate server and remote client)
+                ctx.fireChannelInactive();
+                ctx.disconnect();
+                ctx.close();
+                asyncSshHandlerReader.close();
+                asyncSshHandlerWriter.close();
+            }
+        }, new AsyncSshHandlerReader.ReadMsgHandler() {
+            @Override
+            public void onMessageRead(final ByteBuf msg) {
+                if(logger.isTraceEnabled()) {
+                    logger.trace("Forwarding message for client: {} on channel: {}, message: {}",
+                            netconfHelloMessageAdditionalHeader.getAddress(), ctx.channel(), AsyncSshHandlerWriter.byteBufToString(msg));
+                }
+                // Just forward to delegate
+                ctx.writeAndFlush(msg);
+            }
+        }, "ssh" + netconfHelloMessageAdditionalHeader.getAddress(), in);
+
+
+        super.channelActive(ctx);
+    }
+
+    private void writeAdditionalHeader(final ChannelHandlerContext ctx) {
+        ctx.writeAndFlush(Unpooled.copiedBuffer(netconfHelloMessageAdditionalHeader.toFormattedString().getBytes()));
+    }
+
+    @Override
+    public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
+       asyncSshHandlerWriter.write(ctx, msg, ctx.newPromise());
+    }
+
+    @Override
+    public void channelInactive(final ChannelHandlerContext ctx) throws Exception {
+        logger.debug("Internal connection to netconf server was dropped for client: {} on channel: ",
+                netconfHelloMessageAdditionalHeader.getAddress(), ctx.channel());
+        callback.onExit(1, "Internal connection to netconf server was dropped for client: " +
+                netconfHelloMessageAdditionalHeader.getAddress() + " on channel: " + ctx.channel());
+        super.channelInactive(ctx);
+    }
+
+
+}
diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SshProxyServer.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SshProxyServer.java
new file mode 100644 (file)
index 0000000..0b85cf2
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.ssh;
+
+import com.google.common.collect.Lists;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.local.LocalAddress;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.channels.AsynchronousChannelGroup;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import org.apache.sshd.SshServer;
+import org.apache.sshd.common.FactoryManager;
+import org.apache.sshd.common.KeyPairProvider;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.RuntimeSshException;
+import org.apache.sshd.common.io.IoAcceptor;
+import org.apache.sshd.common.io.IoConnector;
+import org.apache.sshd.common.io.IoHandler;
+import org.apache.sshd.common.io.IoServiceFactory;
+import org.apache.sshd.common.io.IoServiceFactoryFactory;
+import org.apache.sshd.common.io.nio2.Nio2Acceptor;
+import org.apache.sshd.common.io.nio2.Nio2Connector;
+import org.apache.sshd.common.io.nio2.Nio2ServiceFactoryFactory;
+import org.apache.sshd.common.util.CloseableUtils;
+import org.apache.sshd.server.Command;
+import org.apache.sshd.server.PasswordAuthenticator;
+
+/**
+ * Proxy SSH server that just delegates decrypted content to a delegate server within same VM.
+ * Implemented using Apache Mina SSH lib.
+ */
+public class SshProxyServer implements AutoCloseable {
+
+    private final SshServer sshServer;
+    private final ScheduledExecutorService minaTimerExecutor;
+    private final EventLoopGroup clientGroup;
+    private final IoServiceFactoryFactory nioServiceWithPoolFactoryFactory;
+
+    public SshProxyServer(final ScheduledExecutorService minaTimerExecutor, final EventLoopGroup clientGroup, final ExecutorService nioExecutor) {
+        this.minaTimerExecutor = minaTimerExecutor;
+        this.clientGroup = clientGroup;
+        this.nioServiceWithPoolFactoryFactory = new NioServiceWithPoolFactory.NioServiceWithPoolFactoryFactory(nioExecutor);
+        this.sshServer = SshServer.setUpDefaultServer();
+    }
+
+    public void bind(final InetSocketAddress bindingAddress, final LocalAddress localAddress, final PasswordAuthenticator authenticator, final KeyPairProvider keyPairProvider) throws IOException {
+        sshServer.setHost(bindingAddress.getHostString());
+        sshServer.setPort(bindingAddress.getPort());
+
+        sshServer.setPasswordAuthenticator(authenticator);
+        sshServer.setKeyPairProvider(keyPairProvider);
+
+        sshServer.setIoServiceFactoryFactory(nioServiceWithPoolFactoryFactory);
+        sshServer.setScheduledExecutorService(minaTimerExecutor);
+
+        final RemoteNetconfCommand.NetconfCommandFactory netconfCommandFactory =
+                new RemoteNetconfCommand.NetconfCommandFactory(clientGroup, localAddress);
+        sshServer.setSubsystemFactories(Lists.<NamedFactory<Command>>newArrayList(netconfCommandFactory));
+        sshServer.start();
+    }
+
+    @Override
+    public void close() {
+        try {
+            sshServer.stop(true);
+        } catch (final InterruptedException e) {
+            throw new RuntimeException("Interrupted while stopping sshServer", e);
+        } finally {
+            sshServer.close(true);
+        }
+    }
+
+    /**
+     * Based on Nio2ServiceFactory with one addition: injectable executor
+     */
+    private static final class NioServiceWithPoolFactory extends CloseableUtils.AbstractCloseable implements IoServiceFactory {
+
+        private final FactoryManager manager;
+        private final AsynchronousChannelGroup group;
+
+        public NioServiceWithPoolFactory(final FactoryManager manager, final ExecutorService executor) {
+            this.manager = manager;
+            try {
+                group = AsynchronousChannelGroup.withThreadPool(executor);
+            } catch (final IOException e) {
+                throw new RuntimeSshException(e);
+            }
+        }
+
+        public IoConnector createConnector(final IoHandler handler) {
+            return new Nio2Connector(manager, handler, group);
+        }
+
+        public IoAcceptor createAcceptor(final IoHandler handler) {
+            return new Nio2Acceptor(manager, handler, group);
+        }
+
+        @Override
+        protected void doCloseImmediately() {
+            try {
+                group.shutdownNow();
+                group.awaitTermination(5, TimeUnit.SECONDS);
+            } catch (final Exception e) {
+                log.debug("Exception caught while closing channel group", e);
+            } finally {
+                super.doCloseImmediately();
+            }
+        }
+
+        private static final class NioServiceWithPoolFactoryFactory extends Nio2ServiceFactoryFactory {
+
+            private final ExecutorService nioExecutor;
+
+            private NioServiceWithPoolFactoryFactory(final ExecutorService nioExecutor) {
+                this.nioExecutor = nioExecutor;
+            }
+
+            @Override
+            public IoServiceFactory create(final FactoryManager manager) {
+                return new NioServiceWithPoolFactory(manager, nioExecutor);
+            }
+        }
+    }
+
+}
diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/AuthProviderTracker.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/AuthProviderTracker.java
new file mode 100644 (file)
index 0000000..97e611c
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.ssh.osgi;
+
+import com.google.common.base.Preconditions;
+import org.apache.sshd.server.PasswordAuthenticator;
+import org.apache.sshd.server.session.ServerSession;
+import org.opendaylight.controller.netconf.auth.AuthConstants;
+import org.opendaylight.controller.netconf.auth.AuthProvider;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class AuthProviderTracker implements ServiceTrackerCustomizer<AuthProvider, AuthProvider>, PasswordAuthenticator {
+    private static final Logger logger = LoggerFactory.getLogger(AuthProviderTracker.class);
+
+    private final BundleContext bundleContext;
+
+    private Integer maxPreference;
+    private final ServiceTracker<AuthProvider, AuthProvider> listenerTracker;
+    private AuthProvider authProvider;
+
+    public AuthProviderTracker(final BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+        listenerTracker = new ServiceTracker<>(bundleContext, AuthProvider.class, this);
+        listenerTracker.open();
+    }
+
+    @Override
+    public AuthProvider addingService(final ServiceReference<AuthProvider> reference) {
+        logger.trace("Service {} added", reference);
+        final AuthProvider authService = bundleContext.getService(reference);
+        final Integer newServicePreference = getPreference(reference);
+        if(isBetter(newServicePreference)) {
+            maxPreference = newServicePreference;
+            this.authProvider = authService;
+        }
+        return authService;
+    }
+
+    private Integer getPreference(final ServiceReference<AuthProvider> reference) {
+        final Object preferenceProperty = reference.getProperty(AuthConstants.SERVICE_PREFERENCE_KEY);
+        return preferenceProperty == null ? Integer.MIN_VALUE : Integer.valueOf(preferenceProperty.toString());
+    }
+
+    private boolean isBetter(final Integer newServicePreference) {
+        Preconditions.checkNotNull(newServicePreference);
+        if(maxPreference == null) {
+            return true;
+        }
+
+        return newServicePreference > maxPreference;
+    }
+
+    @Override
+    public void modifiedService(final ServiceReference<AuthProvider> reference, final AuthProvider service) {
+        final AuthProvider authService = bundleContext.getService(reference);
+        final Integer newServicePreference = getPreference(reference);
+        if(isBetter(newServicePreference)) {
+            logger.trace("Replacing modified service {} in netconf SSH.", reference);
+            this.authProvider = authService;
+        }
+    }
+
+    @Override
+    public void removedService(final ServiceReference<AuthProvider> reference, final AuthProvider service) {
+        logger.trace("Removing service {} from netconf SSH. " +
+                "SSH won't authenticate users until AuthProvider service will be started.", reference);
+        maxPreference = null;
+        this.authProvider = null;
+    }
+
+    public void stop() {
+        listenerTracker.close();
+        // sshThread should finish normally since sshServer.close stops processing
+    }
+
+    @Override
+    public boolean authenticate(final String username, final String password, final ServerSession session) {
+        return authProvider == null ? false : authProvider.authenticated(username, password);
+    }
+}
index 0d0f95c3cb4d0856ba56c470f0890eb51371caa1..b871d19db8f062d0dbca93cc18ce6c3c6e09ba2d 100644 (file)
@@ -9,51 +9,51 @@ package org.opendaylight.controller.netconf.ssh.osgi;
 
 import static com.google.common.base.Preconditions.checkState;
 
-import com.google.common.base.Preconditions;
-import java.io.File;
+import com.google.common.base.Optional;
+import com.google.common.base.Strings;
+import io.netty.channel.local.LocalAddress;
+import io.netty.channel.nio.NioEventLoopGroup;
 import java.io.IOException;
 import java.net.InetSocketAddress;
-
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadFactory;
 import org.apache.commons.io.FilenameUtils;
-import org.opendaylight.controller.netconf.auth.AuthConstants;
-import org.opendaylight.controller.netconf.auth.AuthProvider;
-import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
-import org.opendaylight.controller.netconf.ssh.authentication.PEMGenerator;
+import org.apache.sshd.common.util.ThreadUtils;
+import org.apache.sshd.server.keyprovider.PEMGeneratorHostKeyProvider;
+import org.opendaylight.controller.netconf.ssh.SshProxyServer;
 import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil;
 import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil.InfixProp;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
-import org.osgi.util.tracker.ServiceTracker;
-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.Strings;
-
-import io.netty.channel.EventLoopGroup;
-import io.netty.channel.local.LocalAddress;
-import io.netty.channel.nio.NioEventLoopGroup;
-
-/**
- * Activator for netconf SSH bundle which creates SSH bridge between netconf client and netconf server. Activator
- * starts SSH Server in its own thread. This thread is closed when activator calls stop() method. Server opens socket
- * and listens for client connections. Each client connection creation is handled in separate
- * {@link org.opendaylight.controller.netconf.ssh.threads.Handshaker} thread.
- * This thread creates two additional threads {@link org.opendaylight.controller.netconf.ssh.threads.IOThread}
- * forwarding data from/to client.IOThread closes servers session and server connection when it gets -1 on input stream.
- * {@link org.opendaylight.controller.netconf.ssh.threads.IOThread}'s run method waits for -1 on input stream to finish.
- * All threads are daemons.
- */
 public class NetconfSSHActivator implements BundleActivator {
     private static final Logger logger = LoggerFactory.getLogger(NetconfSSHActivator.class);
-    private static AuthProviderTracker authProviderTracker;
 
-    private NetconfSSHServer server;
+    private static final java.lang.String ALGORITHM = "RSA";
+    private static final int KEY_SIZE = 4096;
+    public static final int POOL_SIZE = 8;
+
+    private ScheduledExecutorService minaTimerExecutor;
+    private NioEventLoopGroup clientGroup;
+    private ExecutorService nioExecutor;
+    private AuthProviderTracker authProviderTracker;
+
+    private SshProxyServer server;
 
     @Override
     public void start(final BundleContext bundleContext) throws IOException {
+        minaTimerExecutor = Executors.newScheduledThreadPool(POOL_SIZE, new ThreadFactory() {
+            @Override
+            public Thread newThread(final Runnable r) {
+                return new Thread(r, "netconf-ssh-server-mina-timers");
+            }
+        });
+        clientGroup = new NioEventLoopGroup();
+        nioExecutor = ThreadUtils.newFixedThreadPool("netconf-ssh-server-nio-group", POOL_SIZE);
         server = startSSHServer(bundleContext);
     }
 
@@ -66,11 +66,22 @@ public class NetconfSSHActivator implements BundleActivator {
         if(authProviderTracker != null) {
             authProviderTracker.stop();
         }
+
+        if(nioExecutor!=null) {
+            nioExecutor.shutdownNow();
+        }
+
+        if(clientGroup != null) {
+            clientGroup.shutdownGracefully();
+        }
+
+        if(minaTimerExecutor != null) {
+            minaTimerExecutor.shutdownNow();
+        }
     }
 
-    private static NetconfSSHServer startSSHServer(final BundleContext bundleContext) throws IOException {
-        final Optional<InetSocketAddress> maybeSshSocketAddress = NetconfConfigUtil.extractNetconfServerAddress(bundleContext,
-                InfixProp.ssh);
+    private SshProxyServer startSSHServer(final BundleContext bundleContext) throws IOException {
+        final Optional<InetSocketAddress> maybeSshSocketAddress = NetconfConfigUtil.extractNetconfServerAddress(bundleContext, InfixProp.ssh);
 
         if (maybeSshSocketAddress.isPresent() == false) {
             logger.trace("SSH bridge not configured");
@@ -82,92 +93,15 @@ public class NetconfSSHActivator implements BundleActivator {
 
         final LocalAddress localAddress = NetconfConfigUtil.getNetconfLocalAddress();
 
-        final String path = FilenameUtils.separatorsToSystem(NetconfConfigUtil.getPrivateKeyPath(bundleContext));
-        checkState(!Strings.isNullOrEmpty(path), "Path to ssh private key is blank. Reconfigure %s", NetconfConfigUtil.getPrivateKeyKey());
-        final String privateKeyPEMString = PEMGenerator.readOrGeneratePK(new File(path));
-
-        final EventLoopGroup bossGroup  = new NioEventLoopGroup();
-        final NetconfSSHServer server = NetconfSSHServer.start(sshSocketAddress.getPort(), localAddress, bossGroup, privateKeyPEMString.toCharArray());
-
-        authProviderTracker = new AuthProviderTracker(bundleContext, server);
+        authProviderTracker = new AuthProviderTracker(bundleContext);
 
-        return server;
-    }
+        final String path = FilenameUtils.separatorsToSystem(NetconfConfigUtil.getPrivateKeyPath(bundleContext));
+        checkState(!Strings.isNullOrEmpty(path), "Path to ssh private key is blank. Reconfigure %s",
+                NetconfConfigUtil.getPrivateKeyKey());
 
-    private static Thread runNetconfSshThread(final NetconfSSHServer server) {
-        final Thread serverThread = new Thread(server, "netconf SSH server thread");
-        serverThread.setDaemon(true);
-        serverThread.start();
-        logger.trace("Netconf SSH  bridge up and running.");
-        return serverThread;
+        final SshProxyServer sshProxyServer = new SshProxyServer(minaTimerExecutor, clientGroup, nioExecutor);
+        sshProxyServer.bind(sshSocketAddress, localAddress, authProviderTracker, new PEMGeneratorHostKeyProvider(path, ALGORITHM, KEY_SIZE));
+        return sshProxyServer;
     }
 
-    private static class AuthProviderTracker implements ServiceTrackerCustomizer<AuthProvider, AuthProvider> {
-        private final BundleContext bundleContext;
-        private final NetconfSSHServer server;
-
-        private Integer maxPreference;
-        private Thread sshThread;
-        private final ServiceTracker<AuthProvider, AuthProvider> listenerTracker;
-
-        public AuthProviderTracker(final BundleContext bundleContext, final NetconfSSHServer server) {
-            this.bundleContext = bundleContext;
-            this.server = server;
-            listenerTracker = new ServiceTracker<>(bundleContext, AuthProvider.class, this);
-            listenerTracker.open();
-        }
-
-        @Override
-        public AuthProvider addingService(final ServiceReference<AuthProvider> reference) {
-            logger.trace("Service {} added", reference);
-            final AuthProvider authService = bundleContext.getService(reference);
-            final Integer newServicePreference = getPreference(reference);
-            if(isBetter(newServicePreference)) {
-                maxPreference = newServicePreference;
-                server.setAuthProvider(authService);
-                if(sshThread == null) {
-                    sshThread = runNetconfSshThread(server);
-                }
-            }
-            return authService;
-        }
-
-        private Integer getPreference(final ServiceReference<AuthProvider> reference) {
-            final Object preferenceProperty = reference.getProperty(AuthConstants.SERVICE_PREFERENCE_KEY);
-            return preferenceProperty == null ? Integer.MIN_VALUE : Integer.valueOf(preferenceProperty.toString());
-        }
-
-        private boolean isBetter(final Integer newServicePreference) {
-            Preconditions.checkNotNull(newServicePreference);
-            if(maxPreference == null) {
-                return true;
-            }
-
-            return newServicePreference > maxPreference;
-        }
-
-        @Override
-        public void modifiedService(final ServiceReference<AuthProvider> reference, final AuthProvider service) {
-            final AuthProvider authService = bundleContext.getService(reference);
-            final Integer newServicePreference = getPreference(reference);
-            if(isBetter(newServicePreference)) {
-                logger.trace("Replacing modified service {} in netconf SSH.", reference);
-                server.setAuthProvider(authService);
-            }
-        }
-
-        @Override
-        public void removedService(final ServiceReference<AuthProvider> reference, final AuthProvider service) {
-            logger.trace("Removing service {} from netconf SSH. " +
-                    "SSH won't authenticate users until AuthProvider service will be started.", reference);
-            maxPreference = null;
-            server.setAuthProvider(null);
-        }
-
-        public void stop() {
-            listenerTracker.close();
-            // sshThread should finish normally since sshServer.close stops processing
-        }
-
-    }
 }
index c9de92b9d5e22799233a846e4ec1100041dcb025..0172a28c16b0d0a98e43665cec3339863623bd3c 100644 (file)
             <artifactId>logback-classic</artifactId>
             <scope>compile</scope>
         </dependency>
+        <dependency>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcpkix-jdk15on</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcprov-jdk15on</artifactId>
+        </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>netconf-netty-util</artifactId>
         </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>netconf-auth</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>commons.logback_settings</artifactId>
             <groupId>xmlunit</groupId>
             <artifactId>xmlunit</artifactId>
         </dependency>
-
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>config-util</artifactId>
             <groupId>${project.groupId}</groupId>
             <artifactId>netconf-api</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>ietf-netconf-monitoring</artifactId>
+        </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>netconf-client</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools.model</groupId>
+            <artifactId>ietf-yang-types-20130715</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools.model</groupId>
+            <artifactId>ietf-inet-types</artifactId>
+        </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>netconf-impl</artifactId>
             <groupId>${project.groupId}</groupId>
             <artifactId>netconf-monitoring</artifactId>
         </dependency>
-
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>netconf-ssh</artifactId>
         </dependency>
-
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>netty-config-api</artifactId>
diff --git a/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/DataList.java b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/DataList.java
new file mode 100644 (file)
index 0000000..d6dd55c
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.test.tool;
+
+import java.util.Collections;
+import java.util.List;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+
+public class DataList {
+
+    private List<XmlElement> configList = Collections.emptyList();
+
+    public List<XmlElement> getConfigList() {
+        return configList;
+    }
+
+    public void setConfigList(List<XmlElement> configList) {
+        this.configList = configList;
+    }
+
+    public void resetConfigList() {
+        configList = Collections.emptyList();
+    }
+
+}
index 56e3452a7759c7c458d26e8149221c223569373f..681b9a6a2d1e0915599a36eeb86035c8b2ba72bb 100644 (file)
@@ -12,31 +12,38 @@ import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
 
+import ch.qos.logback.classic.Level;
+import com.google.common.base.Charsets;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import com.google.common.io.ByteStreams;
+import com.google.common.io.CharStreams;
 import com.google.common.io.Files;
 import java.io.File;
+import java.io.FileFilter;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
-
 import java.util.concurrent.TimeUnit;
 import net.sourceforge.argparse4j.ArgumentParsers;
 import net.sourceforge.argparse4j.annotation.Arg;
 import net.sourceforge.argparse4j.inf.ArgumentParser;
 import net.sourceforge.argparse4j.inf.ArgumentParserException;
-
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Charsets;
-import com.google.common.io.CharStreams;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
 
 public final class Main {
 
-    // TODO add logback config
-
-    // TODO make exi configurable
-
     private static final Logger LOG = LoggerFactory.getLogger(Main.class);
 
     static class Params {
@@ -56,8 +63,8 @@ public final class Main {
         @Arg(dest = "generate-config-address")
         public String generateConfigsAddress;
 
-        @Arg(dest = "generate-configs-dir")
-        public File generateConfigsDir;
+        @Arg(dest = "distro-folder")
+        public File distroFolder;
 
         @Arg(dest = "generate-configs-batch-size")
         public int generateConfigBatchSize;
@@ -68,9 +75,15 @@ public final class Main {
         @Arg(dest = "exi")
         public boolean exi;
 
+        @Arg(dest = "debug")
+        public boolean debug;
+
         static ArgumentParser getParser() {
             final ArgumentParser parser = ArgumentParsers.newArgumentParser("netconf testool");
-            parser.addArgument("--devices-count")
+
+            parser.description("Netconf device simulator. Detailed info can be found at https://wiki.opendaylight.org/view/OpenDaylight_Controller:Netconf:Testtool#Building_testtool");
+
+            parser.addArgument("--device-count")
                     .type(Integer.class)
                     .setDefault(1)
                     .type(Integer.class)
@@ -79,8 +92,7 @@ public final class Main {
 
             parser.addArgument("--schemas-dir")
                     .type(File.class)
-                    .required(true)
-                    .help("Directory containing yang schemas to describe simulated devices")
+                    .help("Directory containing yang schemas to describe simulated devices. Some schemas e.g. netconf monitoring and inet types are included by default")
                     .dest("schemas-dir");
 
             parser.addArgument("--starting-port")
@@ -91,7 +103,7 @@ public final class Main {
 
             parser.addArgument("--generate-config-connection-timeout")
                     .type(Integer.class)
-                    .setDefault((int)TimeUnit.MINUTES.toMillis(5))
+                    .setDefault((int)TimeUnit.MINUTES.toMillis(30))
                     .help("Timeout to be generated in initial config files")
                     .dest("generate-config-connection-timeout");
 
@@ -103,14 +115,14 @@ public final class Main {
 
             parser.addArgument("--generate-configs-batch-size")
                     .type(Integer.class)
-                    .setDefault(100)
+                    .setDefault(4000)
                     .help("Number of connector configs per generated file")
                     .dest("generate-configs-batch-size");
 
-            parser.addArgument("--generate-configs-dir")
+            parser.addArgument("--distribution-folder")
                     .type(File.class)
-                    .help("Directory where initial config files for ODL distribution should be generated")
-                    .dest("generate-configs-dir");
+                    .help("Directory where the karaf distribution for controller is located")
+                    .dest("distro-folder");
 
             parser.addArgument("--ssh")
                     .type(Boolean.class)
@@ -120,10 +132,16 @@ public final class Main {
 
             parser.addArgument("--exi")
                     .type(Boolean.class)
-                    .setDefault(false)
+                    .setDefault(true)
                     .help("Whether to use exi to transport xml content")
                     .dest("exi");
 
+            parser.addArgument("--debug")
+                    .type(Boolean.class)
+                    .setDefault(false)
+                    .help("Whether to use debug log level instead of INFO")
+                    .dest("debug");
+
             return parser;
         }
 
@@ -131,23 +149,29 @@ public final class Main {
             checkArgument(deviceCount > 0, "Device count has to be > 0");
             checkArgument(startingPort > 1024, "Starting port has to be > 1024");
 
-            checkArgument(schemasDir.exists(), "Schemas dir has to exist");
-            checkArgument(schemasDir.isDirectory(), "Schemas dir has to be a directory");
-            checkArgument(schemasDir.canRead(), "Schemas dir has to be readable");
+            if(schemasDir != null) {
+                checkArgument(schemasDir.exists(), "Schemas dir has to exist");
+                checkArgument(schemasDir.isDirectory(), "Schemas dir has to be a directory");
+                checkArgument(schemasDir.canRead(), "Schemas dir has to be readable");
+            }
         }
     }
 
     public static void main(final String[] args) {
-        ch.ethz.ssh2.log.Logger.enabled = true;
-
         final Params params = parseArgs(args, Params.getParser());
         params.validate();
 
+        final ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
+        root.setLevel(params.debug ? Level.DEBUG : Level.INFO);
+
         final NetconfDeviceSimulator netconfDeviceSimulator = new NetconfDeviceSimulator();
         try {
             final List<Integer> openDevices = netconfDeviceSimulator.start(params);
-            if(params.generateConfigsDir != null) {
-                new ConfigGenerator(params.generateConfigsDir, openDevices).generate(params.ssh, params.generateConfigBatchSize, params.generateConfigsTimeout, params.generateConfigsAddress);
+            if(params.distroFolder != null) {
+                final ConfigGenerator configGenerator = new ConfigGenerator(params.distroFolder, openDevices);
+                final List<File> generated = configGenerator.generate(params.ssh, params.generateConfigBatchSize, params.generateConfigsTimeout, params.generateConfigsAddress);
+                configGenerator.updateFeatureFile(generated);
+                configGenerator.changeLoadOrder();
             }
         } catch (final Exception e) {
             LOG.error("Unhandled exception", e);
@@ -165,7 +189,6 @@ public final class Main {
         }
     }
 
-
     private static Params parseArgs(final String[] args, final ArgumentParser parser) {
         final Params opt = new Params();
         try {
@@ -187,24 +210,45 @@ public final class Main {
         public static final String NETCONF_USE_SSH = "false";
         public static final String SIM_DEVICE_SUFFIX = "-sim-device";
 
-        private final File directory;
+        private static final String SIM_DEVICE_CFG_PREFIX = "simulated-devices_";
+        private static final String ETC_KARAF_PATH = "etc/";
+        private static final String ETC_OPENDAYLIGHT_KARAF_PATH = ETC_KARAF_PATH + "opendaylight/karaf/";
+
+        public static final String NETCONF_CONNECTOR_ALL_FEATURE = "odl-netconf-connector-all";
+        private static final String ORG_OPS4J_PAX_URL_MVN_CFG = "org.ops4j.pax.url.mvn.cfg";
+
+        private final File configDir;
         private final List<Integer> openDevices;
+        private final File ncFeatureFile;
+        private final File etcDir;
+        private final File loadOrderCfgFile;
 
         public ConfigGenerator(final File directory, final List<Integer> openDevices) {
-            this.directory = directory;
+            this.configDir = new File(directory, ETC_OPENDAYLIGHT_KARAF_PATH);
+            this.etcDir = new File(directory, ETC_KARAF_PATH);
+            this.loadOrderCfgFile = new File(etcDir, ORG_OPS4J_PAX_URL_MVN_CFG);
+            this.ncFeatureFile = getFeatureFile(directory, "features-netconf-connector");
             this.openDevices = openDevices;
         }
 
-        public void generate(final boolean useSsh, final int batchSize, final int generateConfigsTimeout, final String address) {
-            if(directory.exists() == false) {
-                checkState(directory.mkdirs(), "Unable to create folder %s" + directory);
+        public List<File> generate(final boolean useSsh, final int batchSize, final int generateConfigsTimeout, final String address) {
+            if(configDir.exists() == false) {
+                Preconditions.checkState(configDir.mkdirs(), "Unable to create directory " + configDir);
+            }
+
+            for (final File file : configDir.listFiles(new FileFilter() {
+                @Override
+                public boolean accept(final File pathname) {
+                    return !pathname.isDirectory() && pathname.getName().startsWith(SIM_DEVICE_CFG_PREFIX);
+                }
+            })) {
+                Preconditions.checkState(file.delete(), "Unable to clean previous generated file %s", file);
             }
 
             try(InputStream stream = Main.class.getResourceAsStream(NETCONF_CONNECTOR_XML)) {
                 checkNotNull(stream, "Cannot load %s", NETCONF_CONNECTOR_XML);
                 String configBlueprint = CharStreams.toString(new InputStreamReader(stream, Charsets.UTF_8));
 
-                // TODO make address configurable
                 checkState(configBlueprint.contains(NETCONF_CONNECTOR_NAME));
                 checkState(configBlueprint.contains(NETCONF_CONNECTOR_PORT));
                 checkState(configBlueprint.contains(NETCONF_USE_SSH));
@@ -223,6 +267,8 @@ public final class Main {
                 StringBuilder b = new StringBuilder();
                 b.append(before);
 
+                final List<File> generatedConfigs = Lists.newArrayList();
+
                 for (final Integer openDevice : openDevices) {
                     if(batchStart == null) {
                         batchStart = openDevice;
@@ -236,7 +282,9 @@ public final class Main {
                     connectorCount++;
                     if(connectorCount == batchSize) {
                         b.append(after);
-                        Files.write(b.toString(), new File(directory, String.format("simulated-devices_%d-%d.xml", batchStart, openDevice)), Charsets.UTF_8);
+                        final File to = new File(configDir, String.format(SIM_DEVICE_CFG_PREFIX + "%d-%d.xml", batchStart, openDevice));
+                        generatedConfigs.add(to);
+                        Files.write(b.toString(), to, Charsets.UTF_8);
                         connectorCount = 0;
                         b = new StringBuilder();
                         b.append(before);
@@ -247,13 +295,100 @@ public final class Main {
                 // Write remaining
                 if(connectorCount != 0) {
                     b.append(after);
-                    Files.write(b.toString(), new File(directory, String.format("simulated-devices_%d-%d.xml", batchStart, openDevices.get(openDevices.size() - 1))), Charsets.UTF_8);
+                    final File to = new File(configDir, String.format(SIM_DEVICE_CFG_PREFIX + "%d-%d.xml", batchStart, openDevices.get(openDevices.size() - 1)));
+                    generatedConfigs.add(to);
+                    Files.write(b.toString(), to, Charsets.UTF_8);
                 }
 
-                LOG.info("Config files generated in {}", directory);
+                LOG.info("Config files generated in {}", configDir);
+                return generatedConfigs;
             } catch (final IOException e) {
                 throw new RuntimeException("Unable to generate config files", e);
             }
         }
+
+
+        public void updateFeatureFile(final List<File> generated) {
+            // TODO karaf core contains jaxb for feature files, use that for modification
+            try {
+                final Document document = XmlUtil.readXmlToDocument(Files.toString(ncFeatureFile, Charsets.UTF_8));
+                final NodeList childNodes = document.getDocumentElement().getChildNodes();
+
+                for (int i = 0; i < childNodes.getLength(); i++) {
+                    final Node item = childNodes.item(i);
+                    if(item instanceof Element == false) {
+                        continue;
+                    }
+                    if(item.getLocalName().equals("feature") ==false) {
+                        continue;
+                    }
+
+                    if(NETCONF_CONNECTOR_ALL_FEATURE.equals(((Element) item).getAttribute("name"))) {
+                        final Element ncAllFeatureDefinition = (Element) item;
+                        // Clean previous generated files
+                        for (final XmlElement configfile : XmlElement.fromDomElement(ncAllFeatureDefinition).getChildElements("configfile")) {
+                            ncAllFeatureDefinition.removeChild(configfile.getDomElement());
+                        }
+                        for (final File file : generated) {
+                            final Element configfile = document.createElement("configfile");
+                            configfile.setTextContent("file:" + ETC_OPENDAYLIGHT_KARAF_PATH + file.getName());
+                            configfile.setAttribute("finalname", ETC_OPENDAYLIGHT_KARAF_PATH + file.getName());
+                            ncAllFeatureDefinition.appendChild(configfile);
+                        }
+                    }
+                }
+
+                Files.write(XmlUtil.toString(document), ncFeatureFile, Charsets.UTF_8);
+                LOG.info("Feature file {} updated", ncFeatureFile);
+            } catch (final IOException e) {
+                throw new RuntimeException("Unable to load features file as a resource");
+            } catch (final SAXException e) {
+                throw new RuntimeException("Unable to parse features file");
+            }
+        }
+
+
+        private static File getFeatureFile(final File distroFolder, final String featureName) {
+            checkExistingDir(distroFolder, String.format("Folder %s does not exist", distroFolder));
+
+            final File systemDir = checkExistingDir(new File(distroFolder, "system"), String.format("Folder %s does not contain a karaf distro, folder system is missing", distroFolder));
+            final File netconfConnectorFeaturesParentDir = checkExistingDir(new File(systemDir, "org/opendaylight/controller/" + featureName), String.format("Karaf distro in %s does not contain netconf-connector features", distroFolder));
+
+            // Find newest version for features
+            final File newestVersionDir = Collections.max(
+                    Lists.newArrayList(netconfConnectorFeaturesParentDir.listFiles(new FileFilter() {
+                        @Override
+                        public boolean accept(final File pathname) {
+                            return pathname.isDirectory();
+                        }
+                    })), new Comparator<File>() {
+                        @Override
+                        public int compare(final File o1, final File o2) {
+                            return o1.getName().compareTo(o2.getName());
+                        }
+                    });
+
+            return newestVersionDir.listFiles(new FileFilter() {
+                @Override
+                public boolean accept(final File pathname) {
+                    return pathname.getName().contains(featureName);
+                }
+            })[0];
+        }
+
+        private static File checkExistingDir(final File folder, final String msg) {
+            Preconditions.checkArgument(folder.exists(), msg);
+            Preconditions.checkArgument(folder.isDirectory(), msg);
+            return folder;
+        }
+
+        public void changeLoadOrder() {
+            try {
+                Files.write(ByteStreams.toByteArray(getClass().getResourceAsStream("/" +ORG_OPS4J_PAX_URL_MVN_CFG)), loadOrderCfgFile);
+                LOG.info("Load order changed to prefer local bundles/features by rewriting file {}", loadOrderCfgFile);
+            } catch (IOException e) {
+                throw new RuntimeException("Unable to rewrite features file " + loadOrderCfgFile, e);
+            }
+        }
     }
 }
index 600baa743169744a9e2019ef116ee98f4a194c4e..e8ba769da547f552dc3fe47aaa9a6e3f35ad0d54 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.controller.netconf.test.tool;
 
 import com.google.common.base.Charsets;
 import com.google.common.base.Function;
+import com.google.common.base.Objects;
 import com.google.common.base.Optional;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.Lists;
@@ -17,20 +18,24 @@ import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import com.google.common.io.CharStreams;
 import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelFuture;
 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.InputStream;
 import java.io.InputStreamReader;
 import java.lang.management.ManagementFactory;
 import java.net.Inet4Address;
 import java.net.InetSocketAddress;
 import java.net.URI;
 import java.net.UnknownHostException;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.AbstractMap;
 import java.util.Date;
 import java.util.HashMap;
@@ -39,8 +44,15 @@ import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
 import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
 import org.antlr.v4.runtime.ParserRuleContext;
 import org.antlr.v4.runtime.tree.ParseTreeWalker;
+import org.apache.sshd.common.util.ThreadUtils;
+import org.apache.sshd.server.PasswordAuthenticator;
+import org.apache.sshd.server.keyprovider.PEMGeneratorHostKeyProvider;
+import org.apache.sshd.server.session.ServerSession;
 import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
 import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
@@ -55,8 +67,7 @@ import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceSnapshot;
 import org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringOperationService;
-import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
-import org.opendaylight.controller.netconf.ssh.authentication.PEMGenerator;
+import org.opendaylight.controller.netconf.ssh.SshProxyServer;
 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;
@@ -64,6 +75,7 @@ import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
 import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceListener;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider;
 import org.opendaylight.yangtools.yang.model.repo.util.FilesystemSchemaSourceCache;
 import org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils;
 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
@@ -78,19 +90,25 @@ public class NetconfDeviceSimulator implements Closeable {
 
     private static final Logger LOG = LoggerFactory.getLogger(NetconfDeviceSimulator.class);
 
-    public static final int CONNECTION_TIMEOUT_MILLIS = 20000;
-
     private final NioEventLoopGroup nettyThreadgroup;
     private final HashedWheelTimer hashedWheelTimer;
     private final List<Channel> devicesChannels = Lists.newArrayList();
+    private final List<SshProxyServer> sshWrappers = Lists.newArrayList();
+    private final ScheduledExecutorService minaTimerExecutor;
+    private final ExecutorService nioExecutor;
 
     public NetconfDeviceSimulator() {
-        this(new NioEventLoopGroup(), new HashedWheelTimer());
+        // TODO make pool size configurable
+        this(new NioEventLoopGroup(), new HashedWheelTimer(),
+                Executors.newScheduledThreadPool(8, new ThreadFactoryBuilder().setNameFormat("netconf-ssh-server-mina-timers-%d").build()),
+                ThreadUtils.newFixedThreadPool("netconf-ssh-server-nio-group", 8));
     }
 
-    public NetconfDeviceSimulator(final NioEventLoopGroup eventExecutors, final HashedWheelTimer hashedWheelTimer) {
+    private NetconfDeviceSimulator(final NioEventLoopGroup eventExecutors, final HashedWheelTimer hashedWheelTimer, final ScheduledExecutorService minaTimerExecutor, final ExecutorService nioExecutor) {
         this.nettyThreadgroup = eventExecutors;
         this.hashedWheelTimer = hashedWheelTimer;
+        this.minaTimerExecutor = minaTimerExecutor;
+        this.nioExecutor = nioExecutor;
     }
 
     private NetconfServerDispatcher createDispatcher(final Map<ModuleBuilder, String> moduleBuilders, final boolean exi, final int generateConfigsTimeout) {
@@ -123,34 +141,36 @@ public class NetconfDeviceSimulator implements Closeable {
     }
 
     private Map<ModuleBuilder, String> toModuleBuilders(final Map<SourceIdentifier, Map.Entry<ASTSchemaSource, YangTextSchemaSource>> sources) {
-            final Map<SourceIdentifier, ParserRuleContext> asts = Maps.transformValues(sources,  new Function<Map.Entry<ASTSchemaSource, YangTextSchemaSource>, ParserRuleContext>() {
-                @Override
-                public ParserRuleContext apply(final Map.Entry<ASTSchemaSource, YangTextSchemaSource> input) {
-                    return input.getKey().getAST();
-                }
-            });
-            final Map<String, TreeMap<Date, URI>> namespaceContext = BuilderUtils.createYangNamespaceContext(
-                    asts.values(), Optional.<SchemaContext>absent());
+        final Map<SourceIdentifier, ParserRuleContext> asts = Maps.transformValues(sources, new Function<Map.Entry<ASTSchemaSource, YangTextSchemaSource>, ParserRuleContext>() {
+            @Override
+            public ParserRuleContext apply(final Map.Entry<ASTSchemaSource, YangTextSchemaSource> input) {
+                return input.getKey().getAST();
+            }
+        });
+        final Map<String, TreeMap<Date, URI>> namespaceContext = BuilderUtils.createYangNamespaceContext(
+                asts.values(), Optional.<SchemaContext>absent());
 
-            final ParseTreeWalker walker = new ParseTreeWalker();
-            final Map<ModuleBuilder, String> sourceToBuilder = new HashMap<>();
+        final ParseTreeWalker walker = new ParseTreeWalker();
+        final Map<ModuleBuilder, String> sourceToBuilder = new HashMap<>();
 
-            for (final Map.Entry<SourceIdentifier, ParserRuleContext> entry : asts.entrySet()) {
-                final ModuleBuilder moduleBuilder = YangParserListenerImpl.create(namespaceContext, entry.getKey().getName(),
-                        walker, entry.getValue()).getModuleBuilder();
+        for (final Map.Entry<SourceIdentifier, ParserRuleContext> entry : asts.entrySet()) {
+            final ModuleBuilder moduleBuilder = YangParserListenerImpl.create(namespaceContext, entry.getKey().getName(),
+                    walker, entry.getValue()).getModuleBuilder();
 
-                try(InputStreamReader stream = new InputStreamReader(sources.get(entry.getKey()).getValue().openStream(), Charsets.UTF_8)) {
-                    sourceToBuilder.put(moduleBuilder, CharStreams.toString(stream));
-                } catch (final IOException e) {
-                    throw new RuntimeException(e);
-                }
+            try(InputStreamReader stream = new InputStreamReader(sources.get(entry.getKey()).getValue().openStream(), Charsets.UTF_8)) {
+                sourceToBuilder.put(moduleBuilder, CharStreams.toString(stream));
+            } catch (final IOException e) {
+                throw new RuntimeException(e);
             }
-
-            return sourceToBuilder;
         }
 
+        return sourceToBuilder;
+    }
+
 
     public List<Integer> start(final Main.Params params) {
+        LOG.info("Starting {}, {} simulated devices starting on port {}", params.deviceCount, params.ssh ? "SSH" : "TCP", params.startingPort);
+
         final Map<ModuleBuilder, String> moduleBuilders = parseSchemasToModuleBuilders(params);
 
         final NetconfServerDispatcher dispatcher = createDispatcher(moduleBuilders, params.exi, params.generateConfigsTimeout);
@@ -158,17 +178,31 @@ public class NetconfDeviceSimulator implements Closeable {
         int currentPort = params.startingPort;
 
         final List<Integer> openDevices = Lists.newArrayList();
+
+        // Generate key to temp folder
+        final PEMGeneratorHostKeyProvider keyPairProvider = getPemGeneratorHostKeyProvider();
+
         for (int i = 0; i < params.deviceCount; i++) {
             final InetSocketAddress address = getAddress(currentPort);
 
             final ChannelFuture server;
             if(params.ssh) {
+                final InetSocketAddress bindingAddress = InetSocketAddress.createUnresolved("0.0.0.0", currentPort);
                 final LocalAddress tcpLocalAddress = new LocalAddress(address.toString());
 
                 server = dispatcher.createLocalServer(tcpLocalAddress);
                 try {
-                    final NetconfSSHServer sshServer = NetconfSSHServer.start(currentPort, tcpLocalAddress, nettyThreadgroup, getPemArray());
-                    sshServer.setAuthProvider(new AcceptingAuthProvider());
+                    final SshProxyServer sshServer = new SshProxyServer(minaTimerExecutor, nettyThreadgroup, nioExecutor);
+                    sshServer.bind(bindingAddress, tcpLocalAddress,
+                            new PasswordAuthenticator() {
+                                @Override
+                                public boolean authenticate(final String username, final String password, final ServerSession session) {
+                                    // All connections are accepted
+                                    return true;
+                                }
+                            }, keyPairProvider);
+
+                    sshWrappers.add(sshServer);
                 } catch (final Exception e) {
                     LOG.warn("Cannot start simulated device on {}, skipping", address, e);
                     // Close local server and continue
@@ -210,11 +244,10 @@ public class NetconfDeviceSimulator implements Closeable {
 
             devicesChannels.add(server.channel());
             openDevices.add(currentPort - 1);
-
         }
 
         if(openDevices.size() == params.deviceCount) {
-            LOG.info("All simulated devices started successfully from port {} to {}", params.startingPort, currentPort);
+            LOG.info("All simulated devices started successfully from port {} to {}", params.startingPort, currentPort - 1);
         } else {
             LOG.warn("Not all simulated devices started successfully. Started devices ar on ports {}", openDevices);
         }
@@ -222,10 +255,12 @@ public class NetconfDeviceSimulator implements Closeable {
         return openDevices;
     }
 
-    private char[] getPemArray() {
+    private PEMGeneratorHostKeyProvider getPemGeneratorHostKeyProvider() {
         try {
-            return PEMGenerator.readOrGeneratePK(new File("PK")).toCharArray();
+            final Path tempFile = Files.createTempFile("tempKeyNetconfTest", "suffix");
+            return new PEMGeneratorHostKeyProvider(tempFile.toAbsolutePath().toString());
         } catch (final IOException e) {
+            LOG.error("Unable to generate PEM key", e);
             throw new RuntimeException(e);
         }
     }
@@ -251,8 +286,12 @@ public class NetconfDeviceSimulator implements Closeable {
             public void schemaSourceUnregistered(final PotentialSchemaSource<?> potentialSchemaSource) {}
         });
 
-        final FilesystemSchemaSourceCache<YangTextSchemaSource> cache = new FilesystemSchemaSourceCache<>(consumer, YangTextSchemaSource.class, params.schemasDir);
-        consumer.registerSchemaSourceListener(cache);
+        if(params.schemasDir != null) {
+            final FilesystemSchemaSourceCache<YangTextSchemaSource> cache = new FilesystemSchemaSourceCache<>(consumer, YangTextSchemaSource.class, params.schemasDir);
+            consumer.registerSchemaSourceListener(cache);
+        }
+
+        addDefaultSchemas(consumer);
 
         final Map<SourceIdentifier, Map.Entry<ASTSchemaSource, YangTextSchemaSource>> asts = Maps.newHashMap();
         for (final SourceIdentifier loadedSource : loadedSources) {
@@ -269,6 +308,36 @@ public class NetconfDeviceSimulator implements Closeable {
         return toModuleBuilders(asts);
     }
 
+    private void addDefaultSchemas(final SharedSchemaRepository consumer) {
+        SourceIdentifier sId = new SourceIdentifier("ietf-netconf-monitoring", "2010-10-04");
+        registerSource(consumer, "/META-INF/yang/ietf-netconf-monitoring.yang", sId);
+
+        sId = new SourceIdentifier("ietf-yang-types", "2013-07-15");
+        registerSource(consumer, "/META-INF/yang/ietf-yang-types@2013-07-15.yang", sId);
+
+        sId = new SourceIdentifier("ietf-inet-types", "2010-09-24");
+        registerSource(consumer, "/META-INF/yang/ietf-inet-types.yang", sId);
+    }
+
+    private void registerSource(final SharedSchemaRepository consumer, final String resource, final SourceIdentifier sourceId) {
+        consumer.registerSchemaSource(new SchemaSourceProvider<SchemaSourceRepresentation>() {
+            @Override
+            public CheckedFuture<? extends SchemaSourceRepresentation, SchemaSourceException> getSource(final SourceIdentifier sourceIdentifier) {
+                return Futures.immediateCheckedFuture(new YangTextSchemaSource(sourceId) {
+                    @Override
+                    protected Objects.ToStringHelper addToStringAttributes(final Objects.ToStringHelper toStringHelper) {
+                        return toStringHelper;
+                    }
+
+                    @Override
+                    public InputStream openStream() throws IOException {
+                        return getClass().getResourceAsStream(resource);
+                    }
+                });
+            }
+        }, PotentialSchemaSource.create(sourceId, YangTextSchemaSource.class, PotentialSchemaSource.Costs.IMMEDIATE.getValue()));
+    }
+
     private static InetSocketAddress getAddress(final int port) {
         try {
             // TODO make address configurable
@@ -280,10 +349,15 @@ public class NetconfDeviceSimulator implements Closeable {
 
     @Override
     public void close() {
+        for (final SshProxyServer sshWrapper : sshWrappers) {
+            sshWrapper.close();
+        }
         for (final Channel deviceCh : devicesChannels) {
             deviceCh.close();
         }
         nettyThreadgroup.shutdownGracefully();
+        minaTimerExecutor.shutdownNow();
+        nioExecutor.shutdownNow();
         // close Everything
     }
 
@@ -332,11 +406,11 @@ public class NetconfDeviceSimulator implements Closeable {
 
         static class SimulatedOperationService implements NetconfOperationService {
             private final Set<Capability> capabilities;
-            private static SimulatedGet sGet;
+            private final long currentSessionId;
 
             public SimulatedOperationService(final Set<Capability> capabilities, final long currentSessionId) {
                 this.capabilities = capabilities;
-                sGet = new SimulatedGet(String.valueOf(currentSessionId));
+                this.currentSessionId = currentSessionId;
             }
 
             @Override
@@ -346,7 +420,12 @@ public class NetconfDeviceSimulator implements Closeable {
 
             @Override
             public Set<NetconfOperation> getNetconfOperations() {
-                return Sets.<NetconfOperation>newHashSet(sGet);
+                final DataList storage = new DataList();
+                final SimulatedGet sGet = new SimulatedGet(String.valueOf(currentSessionId), storage);
+                final SimulatedEditConfig sEditConfig = new SimulatedEditConfig(String.valueOf(currentSessionId), storage);
+                final SimulatedGetConfig sGetConfig = new SimulatedGetConfig(String.valueOf(currentSessionId), storage);
+                final SimulatedCommit sCommit = new SimulatedCommit(String.valueOf(currentSessionId));
+                return Sets.<NetconfOperation>newHashSet(sGet,  sGetConfig, sEditConfig, sCommit);
             }
 
             @Override
diff --git a/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedCommit.java b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedCommit.java
new file mode 100644 (file)
index 0000000..db3717f
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.test.tool;
+
+import com.google.common.base.Optional;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+class SimulatedCommit extends AbstractConfigNetconfOperation {
+
+    SimulatedCommit(final String netconfSessionIdForReporting) {
+        super(null, netconfSessionIdForReporting);
+    }
+
+    @Override
+    protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException {
+        return XmlUtil.createElement(document, XmlNetconfConstants.OK, Optional.<String>absent());
+    }
+
+    @Override
+    protected String getOperationName() {
+        return XmlNetconfConstants.COMMIT;
+    }
+}
diff --git a/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedEditConfig.java b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedEditConfig.java
new file mode 100644 (file)
index 0000000..e5d068d
--- /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.netconf.test.tool;
+
+import com.google.common.base.Optional;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
+import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfigXmlParser;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+class SimulatedEditConfig extends AbstractConfigNetconfOperation {
+    private static final String DELETE_EDIT_CONFIG = "delete";
+    private static final String OPERATION = "operation";
+    private static final String REMOVE_EDIT_CONFIG = "remove";
+    private final DataList storage;
+
+    SimulatedEditConfig(final String netconfSessionIdForReporting, final DataList storage) {
+        super(null, netconfSessionIdForReporting);
+        this.storage = storage;
+    }
+
+    @Override
+    protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException {
+        final XmlElement configElementData = operationElement.getOnlyChildElement(XmlNetconfConstants.CONFIG_KEY);
+
+        containsDelete(configElementData);
+        if(containsDelete(configElementData)){
+            storage.resetConfigList();
+        } else {
+            storage.setConfigList(configElementData.getChildElements());
+        }
+
+        return XmlUtil.createElement(document, XmlNetconfConstants.OK, Optional.<String>absent());
+    }
+
+    @Override
+      protected String getOperationName() {
+        return EditConfigXmlParser.EDIT_CONFIG;
+    }
+
+    private boolean containsDelete(final XmlElement element) {
+        for (final Attr o : element.getAttributes().values()) {
+            if (o.getLocalName().equals(OPERATION)
+                    && (o.getValue().equals(DELETE_EDIT_CONFIG) || o.getValue()
+                            .equals(REMOVE_EDIT_CONFIG))) {
+                return true;
+            }
+
+        }
+
+        for (final XmlElement xmlElement : element.getChildElements()) {
+            if (containsDelete(xmlElement)) {
+                return true;
+            }
+
+        }
+
+        return false;
+    }
+}
index b1938c833203a63716b5ab3e5951496295b2d371..1c24213ca722cb503c0ba2e519cae09d21e9f4c5 100644 (file)
@@ -19,13 +19,23 @@ import org.w3c.dom.Element;
 
 class SimulatedGet extends AbstractConfigNetconfOperation {
 
-    SimulatedGet(final String netconfSessionIdForReporting) {
+    private final DataList storage;
+
+    SimulatedGet(final String netconfSessionIdForReporting, final DataList storage) {
         super(null, netconfSessionIdForReporting);
+        this.storage = storage;
     }
 
     @Override
     protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException {
-        return XmlUtil.createElement(document, XmlNetconfConstants.DATA_KEY, Optional.<String>absent());
+        final Element element = XmlUtil.createElement(document, XmlNetconfConstants.DATA_KEY, Optional.<String>absent());
+
+        for(final XmlElement e : storage.getConfigList()) {
+            final Element domElement = e.getDomElement();
+            element.appendChild(element.getOwnerDocument().importNode(domElement, true));
+        }
+
+        return element;
     }
 
     @Override
diff --git a/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedGetConfig.java b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedGetConfig.java
new file mode 100644 (file)
index 0000000..cc1258e
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.test.tool;
+
+import com.google.common.base.Optional;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+class SimulatedGetConfig extends AbstractConfigNetconfOperation {
+
+    private final DataList storage;
+
+    SimulatedGetConfig(final String netconfSessionIdForReporting, final DataList storage) {
+        super(null, netconfSessionIdForReporting);
+        this.storage = storage;
+    }
+
+    @Override
+    protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException {
+        final Element element = XmlUtil.createElement(document, XmlNetconfConstants.DATA_KEY, Optional.<String>absent());
+
+        for(final XmlElement e : storage.getConfigList()) {
+            final Element domElement = e.getDomElement();
+            element.appendChild(element.getOwnerDocument().importNode(domElement, true));
+        }
+
+        return element;
+    }
+
+    @Override
+    protected String getOperationName() {
+        return XmlNetconfConstants.GET_CONFIG;
+    }
+}
diff --git a/opendaylight/netconf/netconf-testtool/src/main/resources/org.ops4j.pax.url.mvn.cfg b/opendaylight/netconf/netconf-testtool/src/main/resources/org.ops4j.pax.url.mvn.cfg
new file mode 100644 (file)
index 0000000..9ee45e4
--- /dev/null
@@ -0,0 +1,106 @@
+################################################################################
+#
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+################################################################################
+
+#
+# If set to true, the following property will not allow any certificate to be used
+# when accessing Maven repositories through SSL
+#
+#org.ops4j.pax.url.mvn.certificateCheck=
+
+#
+# Path to the local Maven settings file.
+# The repositories defined in this file will be automatically added to the list
+# of default repositories if the 'org.ops4j.pax.url.mvn.repositories' property
+# below is not set.
+# The following locations are checked for the existence of the settings.xml file
+#   * 1. looks for the specified url
+#   * 2. if not found looks for ${user.home}/.m2/settings.xml
+#   * 3. if not found looks for ${maven.home}/conf/settings.xml
+#   * 4. if not found looks for ${M2_HOME}/conf/settings.xml
+#
+#org.ops4j.pax.url.mvn.settings=
+
+#
+# Path to the local Maven repository which is used to avoid downloading
+# artifacts when they already exist locally.
+# The value of this property will be extracted from the settings.xml file
+# above, or defaulted to:
+#     System.getProperty( "user.home" ) + "/.m2/repository"
+#
+org.ops4j.pax.url.mvn.localRepository=${karaf.home}/${karaf.default.repository}
+
+#
+# Default this to false. It's just weird to use undocumented repos
+#
+org.ops4j.pax.url.mvn.useFallbackRepositories=false
+
+#
+# Uncomment if you don't wanna use the proxy settings
+# from the Maven conf/settings.xml file
+#
+# org.ops4j.pax.url.mvn.proxySupport=false
+
+#
+# Disable aether support by default.  This ensure that the defaultRepositories
+# below will be used
+#
+#org.ops4j.pax.url.mvn.disableAether=true
+
+#
+# Comma separated list of repositories scanned when resolving an artifact.
+# Those repositories will be checked before iterating through the
+#    below list of repositories and even before the local repository
+# A repository url can be appended with zero or more of the following flags:
+#    @snapshots  : the repository contains snaphots
+#    @noreleases : the repository does not contain any released artifacts
+#
+# The following property value will add the system folder as a repo.
+#
+#org.ops4j.pax.url.mvn.defaultRepositories=
+
+# Use the default local repo (e.g.~/.m2/repository) as a "remote" repo
+org.ops4j.pax.url.mvn.defaultLocalRepoAsRemote=false
+
+#
+# Comma separated list of repositories scanned when resolving an artifact.
+# The default list includes the following repositories containing releases:
+#    http://repo1.maven.org/maven2
+#    http://repository.apache.org/content/groups/snapshots-group
+#    http://svn.apache.org/repos/asf/servicemix/m2-repo
+#    http://repository.springsource.com/maven/bundles/release
+#    http://repository.springsource.com/maven/bundles/external
+# To add repositories to the default ones, prepend '+' to the list of repositories
+# to add.
+# A repository url can be appended with zero or more of the following flags:
+#    @snapshots  : the repository contains snaphots
+#    @noreleases : the repository does not contain any released artifacts
+#    @id=reponid : the id for the repository, just like in the settings.xml this is optional but recomendet 
+#
+# The default list doesn't contain any repository containing snapshots as it can impact the artifacts resolution.
+# You may want to add the following repositories containing snapshots:
+#    http://repository.apache.org/content/groups/snapshots-group@id=apache@snapshots@noreleases
+#    http://oss.sonatype.org/content/repositories/snapshots@id=sonatype.snapshots.deploy@snapshots@norelease
+#    http://oss.sonatype.org/content/repositories/ops4j-snapshots@id=ops4j.sonatype.snapshots.deploy@snapshots@noreleases
+#
+org.ops4j.pax.url.mvn.repositories= \
+       file:${karaf.home}/${karaf.default.repository}@id=system.repository, \
+    file:${karaf.data}/kar@id=kar.repository@multi, \
+    http://repo1.maven.org/maven2@id=central, \
+    http://repository.springsource.com/maven/bundles/release@id=spring.ebr.release, \
+    http://repository.springsource.com/maven/bundles/external@id=spring.ebr.external
index 78efe7e9723154bd218bafa5d248af0329fb567d..3c63204881aa9ea0ef3e0909ad302e73187d5b31 100644 (file)
@@ -37,6 +37,8 @@ import org.xml.sax.SAXException;
 
 public final class XmlElement {
 
+    public static final String DEFAULT_NAMESPACE_PREFIX = "";
+
     private final Element element;
     private static final Logger logger = LoggerFactory.getLogger(XmlElement.class);
 
@@ -72,16 +74,16 @@ public final class XmlElement {
         return xmlElement;
     }
 
-    private static Map<String, String> extractNamespaces(Element typeElement) throws NetconfDocumentedException {
+    private Map<String, String> extractNamespaces() throws NetconfDocumentedException {
         Map<String, String> namespaces = new HashMap<>();
-        NamedNodeMap attributes = typeElement.getAttributes();
+        NamedNodeMap attributes = element.getAttributes();
         for (int i = 0; i < attributes.getLength(); i++) {
             Node attribute = attributes.item(i);
             String attribKey = attribute.getNodeName();
             if (attribKey.startsWith(XmlUtil.XMLNS_ATTRIBUTE_KEY)) {
                 String prefix;
                 if (attribKey.equals(XmlUtil.XMLNS_ATTRIBUTE_KEY)) {
-                    prefix = "";
+                    prefix = DEFAULT_NAMESPACE_PREFIX;
                 } else {
                     if (!attribKey.startsWith(XmlUtil.XMLNS_ATTRIBUTE_KEY + ":")){
                         throw new NetconfDocumentedException("Attribute doesn't start with :",
@@ -94,6 +96,15 @@ public final class XmlElement {
                 namespaces.put(prefix, attribute.getNodeValue());
             }
         }
+
+        // namespace does not have to be defined on this element but inherited
+        if(!namespaces.containsKey(DEFAULT_NAMESPACE_PREFIX)) {
+            Optional<String> namespaceOptionally = getNamespaceOptionally();
+            if(namespaceOptionally.isPresent()) {
+                namespaces.put(DEFAULT_NAMESPACE_PREFIX, namespaceOptionally.get());
+            }
+        }
+
         return namespaces;
     }
 
@@ -132,7 +143,7 @@ public final class XmlElement {
     }
 
     public String getName() {
-        if (element.getLocalName()!=null && !element.getLocalName().equals("")){
+        if (element.getLocalName()!=null && !element.getLocalName().equals(DEFAULT_NAMESPACE_PREFIX)){
             return element.getLocalName();
         }
         return element.getTagName();
@@ -327,7 +338,7 @@ public final class XmlElement {
     public String getTextContent() throws NetconfDocumentedException {
         NodeList childNodes = element.getChildNodes();
         if (childNodes.getLength() == 0) {
-            return "";
+            return DEFAULT_NAMESPACE_PREFIX;
         }
         for(int i = 0; i < childNodes.getLength(); i++) {
             Node textChild = childNodes.item(i);
@@ -356,7 +367,7 @@ public final class XmlElement {
 
     public String getNamespaceAttribute() throws MissingNameSpaceException {
         String attribute = element.getAttribute(XmlUtil.XMLNS_ATTRIBUTE_KEY);
-        if (attribute == null || attribute.equals("")){
+        if (attribute == null || attribute.equals(DEFAULT_NAMESPACE_PREFIX)){
             throw new MissingNameSpaceException(String.format("Element %s must specify namespace",
                     toString()),
                     NetconfDocumentedException.ErrorType.application,
@@ -415,14 +426,14 @@ public final class XmlElement {
      * is found value will be null.
      */
     public Map.Entry<String/* prefix */, String/* namespace */> findNamespaceOfTextContent() throws NetconfDocumentedException {
-        Map<String, String> namespaces = extractNamespaces(element);
+        Map<String, String> namespaces = extractNamespaces();
         String textContent = getTextContent();
         int indexOfColon = textContent.indexOf(':');
         String prefix;
         if (indexOfColon > -1) {
             prefix = textContent.substring(0, indexOfColon);
         } else {
-            prefix = "";
+            prefix = DEFAULT_NAMESPACE_PREFIX;
         }
         if (!namespaces.containsKey(prefix)) {
             throw new IllegalArgumentException("Cannot find namespace for " + XmlUtil.toString(element) + ". Prefix from content is "
index 2bb6a2003568cbe5f990f410e6a60f0a22d5d6fa..361f4cfa0866596233f7101b1eb09b13e126fde1 100644 (file)
@@ -37,6 +37,7 @@
     <module>netconf-connector-config</module>
     <module>netconf-auth</module>
     <module>netconf-usermanager</module>
+    <module>netconf-testtool</module>
   </modules>
 
   <dependencies>
         <module>netconf-it</module>
       </modules>
     </profile>
-
-    <profile>
-        <id>testtool</id>
-        <activation>
-            <activeByDefault>false</activeByDefault>
-        </activation>
-        <modules>
-            <module>netconf-testtool</module>
-      </modules>
-    </profile>
   </profiles>
 </project>
index 1ff7ea1444052e84d36e4cf80b440ad9159cd01f..981b175e197242a0e4347b3407ad3cfc86cb3576 100644 (file)
@@ -8,6 +8,15 @@
 
 package org.opendaylight.controller.sal.action;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.opendaylight.controller.sal.core.Property;
+
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlElement;
@@ -32,6 +41,7 @@ public abstract class Action implements Serializable {
     @XmlElement
     protected ActionType type;
     private transient boolean isValid = true;
+    private ConcurrentMap<String, Property> props;
 
     /* Dummy constructor for JAXB */
     public Action() {
@@ -83,6 +93,81 @@ public abstract class Action implements Serializable {
         }
     }
 
+    /**
+     * Gets the list of metadata currently registered with this match
+     *
+     * @return List of metadata currently registered
+     */
+    public List <Property> getMetadatas() {
+        if (this.props != null) {
+            // Return all the values in the map
+            Collection res = this.props.values();
+            if (res == null) {
+                return Collections.emptyList();
+            }
+            return new ArrayList<Property>(res);
+        }
+        return Collections.emptyList();
+    }
+
+    /**
+     * Gets the metadata registered with a name if present
+     *
+     * @param name the name of the property to be extracted
+     *
+     * @return List of metadata currently registered
+     */
+    public Property getMetadata(String name) {
+        if (name == null) {
+            return null;
+        }
+        if (this.props != null) {
+            // Return the Property associated to the name
+            return this.props.get(name);
+        }
+        return null;
+    }
+
+    /**
+     * Sets the metadata associated to a name. If the name or prop is NULL,
+     * an exception NullPointerException will be raised.
+     *
+     * @param name the name of the property to be set
+     * @param prop, property to be set
+     */
+    public void setMetadata(String name, Property prop) {
+        if (this.props == null) {
+            props = new ConcurrentHashMap<String, Property>();
+        }
+
+        if (this.props != null) {
+            this.props.put(name, prop);
+        }
+    }
+
+    /**
+     * Remove the metadata associated to a name. If the name is NULL,
+     * nothing will be removed.
+     *
+     * @param name the name of the property to be set
+     * @param prop, property to be set
+     *
+     * @return List of metadata currently registered
+     */
+    public void removeMetadata(String name) {
+        if (this.props == null) {
+            return;
+        }
+
+        if (this.props != null) {
+            this.props.remove(name);
+        }
+        // It's intentional to keep the this.props still allocated
+        // till the parent data structure will be alive, so to avoid
+        // unnecessary allocation/deallocation, even if it's holding
+        // nothing
+    }
+
     /**
      * Returns the type of this action
      *
index 910695c1e9cbc0ebcfb121b621fb7187305aff37..a00c3dcb3422d6e20c619bd35d616b62fb6bbab3 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
@@ -15,18 +14,22 @@ import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.TreeMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentHashMap;
 
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 
+import org.opendaylight.controller.sal.core.Property;
 import org.opendaylight.controller.sal.utils.EtherTypes;
 import org.opendaylight.controller.sal.utils.IPProtocols;
 import org.opendaylight.controller.sal.utils.NetUtils;
@@ -52,7 +55,9 @@ public class Match implements Cloneable, Serializable {
         reversableMatches = Collections.unmodifiableMap(map);
     }
     private Map<MatchType, MatchField> fields;
-    private int matches; // concise way to tell which fields the match is set for (may remove if not needed)
+    private int matches; // concise way to tell which fields the match
+                         // is set for (may remove if not needed)
+    private ConcurrentMap<String, Property> props;
 
     public Match() {
         fields = new HashMap<MatchType, MatchField>();
@@ -64,6 +69,81 @@ public class Match implements Cloneable, Serializable {
         matches = match.matches;
     }
 
+    /**
+     * Gets the list of metadata currently registered with this match
+     *
+     * @return List of metadata currently registered
+     */
+    public List <Property> getMetadatas() {
+        if (this.props != null) {
+            // Return all the values in the map
+            Collection res = this.props.values();
+            if (res == null) {
+                return Collections.emptyList();
+            }
+            return new ArrayList<Property>(res);
+        }
+        return Collections.emptyList();
+    }
+
+    /**
+     * Gets the metadata registered with a name if present
+     *
+     * @param name the name of the property to be extracted
+     *
+     * @return List of metadata currently registered
+     */
+    public Property getMetadata(String name) {
+        if (name == null) {
+            return null;
+        }
+        if (this.props != null) {
+            // Return the Property associated to the name
+            return this.props.get(name);
+        }
+        return null;
+    }
+
+    /**
+     * Sets the metadata associated to a name. If the name or prop is NULL,
+     * an exception NullPointerException will be raised.
+     *
+     * @param name the name of the property to be set
+     * @param prop, property to be set
+     */
+    public void setMetadata(String name, Property prop) {
+        if (this.props == null) {
+            props = new ConcurrentHashMap<String, Property>();
+        }
+
+        if (this.props != null) {
+            this.props.put(name, prop);
+        }
+    }
+
+    /**
+     * Remove the metadata associated to a name. If the name is NULL,
+     * nothing will be removed.
+     *
+     * @param name the name of the property to be set
+     * @param prop, property to be set
+     *
+     * @return List of metadata currently registered
+     */
+    public void removeMetadata(String name) {
+        if (this.props == null) {
+            return;
+        }
+
+        if (this.props != null) {
+            this.props.remove(name);
+        }
+        // It's intentional to keep the this.props still allocated
+        // till the parent data structure will be alive, so to avoid
+        // unnecessary allocation/deallocation, even if it's holding
+        // nothing
+    }
+
     /**
      * Generic setter for frame/packet/message's header fields against which to match
      * Note: For MAC addresses, please pass the cloned value to this function
index 14f0d83ff670d7343b1b67e59796cdec44223cf9..edcb3e2761fd1e8e02117eecb96c4685fa47d5fc 100644 (file)
@@ -17,6 +17,9 @@ import org.junit.Test;
 import org.junit.Assert;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.Property;
+import org.opendaylight.controller.sal.core.Tables;
+import org.opendaylight.controller.sal.core.Tier;
 import org.opendaylight.controller.sal.utils.EtherTypes;
 import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
 import org.slf4j.Logger;
@@ -269,4 +272,89 @@ public class ActionTest {
                 .createNodeConnector((short) 5, node))));
         Assert.assertFalse(actions.contains(new Controller()));
     }
+
+    @Test
+    public void testMetadata() {
+        Property tier1 = new Tier(1);
+        Property tier2 = new Tier(2);
+        Property table1 = new Tables((byte)0x7f);
+        Action a1 = new PopVlan();
+        List<Property> resprops = null;
+        resprops = a1.getMetadatas();
+        // This should be an empty list
+        Assert.assertTrue(resprops.isEmpty());
+        a1.setMetadata("tier1", tier1);
+        a1.setMetadata("tier2", tier2);
+        a1.setMetadata("table1", table1);
+        resprops = a1.getMetadatas();
+        // Check for the number of elements in it
+        Assert.assertTrue(resprops.size() == 3);
+        // Check if the elements are in it
+        Assert.assertTrue(resprops.contains(tier1));
+        Assert.assertTrue(resprops.contains(tier2));
+        Assert.assertTrue(resprops.contains(table1));
+        // Check for single elements retrieve
+        Assert.assertTrue(a1.getMetadata("tier1").equals(tier1));
+        Assert.assertTrue(a1.getMetadata("tier2").equals(tier2));
+        Assert.assertTrue(a1.getMetadata("table1").equals(table1));
+        // Now remove an element and make sure the remaining are
+        // correct
+        a1.removeMetadata("tier1");
+
+        resprops = a1.getMetadatas();
+        // Check for the number of elements in it
+        Assert.assertTrue(resprops.size() == 2);
+        // Check if the elements are in it
+        Assert.assertFalse(resprops.contains(tier1));
+        Assert.assertTrue(resprops.contains(tier2));
+        Assert.assertTrue(resprops.contains(table1));
+        // Check for single elements retrieve
+        Assert.assertTrue(a1.getMetadata("table1").equals(table1));
+        Assert.assertTrue(a1.getMetadata("tier2").equals(tier2));
+        Assert.assertNull(a1.getMetadata("tier1"));
+
+        // Check for an element never existed
+        Assert.assertNull(a1.getMetadata("table100"));
+
+        // Remove them all
+        a1.removeMetadata("tier2");
+        a1.removeMetadata("table1");
+
+        // Remove also a non-existent one
+        a1.removeMetadata("table100");
+
+        resprops = a1.getMetadatas();
+        // Check there are no elements left
+        Assert.assertTrue(resprops.size() == 0);
+
+        // Now check for exception on setting null values
+        try {
+            a1.setMetadata("foo", null);
+            // The line below should never be reached
+            Assert.assertTrue(false);
+        } catch (NullPointerException nue) {
+            // NPE should be raised for null value
+            Assert.assertTrue(true);
+        }
+
+        // Now check on using null key
+        try {
+            a1.setMetadata(null, table1);
+            // The line below should never be reached
+            Assert.assertTrue(false);
+        } catch (NullPointerException nue) {
+            // NPE should be raised for null value
+            Assert.assertTrue(true);
+        }
+
+        // Now check on using null key and null value
+        try {
+            a1.setMetadata(null, null);
+            // The line below should never be reached
+            Assert.assertTrue(false);
+        } catch (NullPointerException nue) {
+            // NPE should be raised for null value
+            Assert.assertTrue(true);
+        }
+    }
 }
index b88ae034d9aa713c96f4ce3ef633f977d5a223b3..b89b27ffe0a61a1c521bfe8657274081b73cd80e 100644 (file)
@@ -11,11 +11,15 @@ package org.opendaylight.controller.sal.match;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.Arrays;
+import java.util.List;
 
 import org.junit.Assert;
 import org.junit.Test;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.Property;
+import org.opendaylight.controller.sal.core.Tables;
+import org.opendaylight.controller.sal.core.Tier;
 import org.opendaylight.controller.sal.utils.EtherTypes;
 import org.opendaylight.controller.sal.utils.IPProtocols;
 import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
@@ -638,4 +642,89 @@ public class MatchTest {
         // No intersection with null match, empty set
         Assert.assertNull(m6.getIntersection(null));
     }
+
+    @Test
+    public void testMetadata() {
+        Property tier1 = new Tier(1);
+        Property tier2 = new Tier(2);
+        Property table1 = new Tables((byte)0x7f);
+        Match m1 = new Match();
+        List<Property> resprops = null;
+        resprops = m1.getMetadatas();
+        // This should be null
+        Assert.assertTrue(resprops.isEmpty());
+        m1.setMetadata("tier1", tier1);
+        m1.setMetadata("tier2", tier2);
+        m1.setMetadata("table1", table1);
+        resprops = m1.getMetadatas();
+        // Check for the number of elements in it
+        Assert.assertTrue(resprops.size() == 3);
+        // Check if the elements are in it
+        Assert.assertTrue(resprops.contains(tier1));
+        Assert.assertTrue(resprops.contains(tier2));
+        Assert.assertTrue(resprops.contains(table1));
+        // Check for single elements retrieve
+        Assert.assertTrue(m1.getMetadata("tier1").equals(tier1));
+        Assert.assertTrue(m1.getMetadata("tier2").equals(tier2));
+        Assert.assertTrue(m1.getMetadata("table1").equals(table1));
+        // Now remove an element and make sure the remaining are
+        // correct
+        m1.removeMetadata("tier1");
+
+        resprops = m1.getMetadatas();
+        // Check for the number of elements in it
+        Assert.assertTrue(resprops.size() == 2);
+        // Check if the elements are in it
+        Assert.assertFalse(resprops.contains(tier1));
+        Assert.assertTrue(resprops.contains(tier2));
+        Assert.assertTrue(resprops.contains(table1));
+        // Check for single elements retrieve
+        Assert.assertTrue(m1.getMetadata("table1").equals(table1));
+        Assert.assertTrue(m1.getMetadata("tier2").equals(tier2));
+        Assert.assertNull(m1.getMetadata("tier1"));
+
+        // Check for an element never existed
+        Assert.assertNull(m1.getMetadata("table100"));
+
+        // Remove them all
+        m1.removeMetadata("tier2");
+        m1.removeMetadata("table1");
+
+        // Remove also a non-existent one
+        m1.removeMetadata("table100");
+
+        resprops = m1.getMetadatas();
+        // Check there are no elements left
+        Assert.assertTrue(resprops.size() == 0);
+
+        // Now check for exception on setting null values
+        try {
+            m1.setMetadata("foo", null);
+            // The line below should never be reached
+            Assert.assertTrue(false);
+        } catch (NullPointerException nue) {
+            // NPE should be raised for null value
+            Assert.assertTrue(true);
+        }
+
+        // Now check on using null key
+        try {
+            m1.setMetadata(null, table1);
+            // The line below should never be reached
+            Assert.assertTrue(false);
+        } catch (NullPointerException nue) {
+            // NPE should be raised for null value
+            Assert.assertTrue(true);
+        }
+
+        // Now check on using null key and null value
+        try {
+            m1.setMetadata(null, null);
+            // The line below should never be reached
+            Assert.assertTrue(false);
+        } catch (NullPointerException nue) {
+            // NPE should be raised for null value
+            Assert.assertTrue(true);
+        }
+    }
 }
index 0f11284e53a4bce1db970d66ccc1a86cf024dc67..deecf26e0d99227069114722f4b92addf7c136e1 100644 (file)
@@ -77,7 +77,7 @@ public class Activator extends ComponentActivatorAbstractBase {
             c.add(createContainerServiceDependency(containerName).setService(
                     IInventoryService.class).setCallbacks(
                     "setInventoryService", "unsetInventoryService")
-                    .setRequired(false));
+                    .setRequired(true));
             c.add(createContainerServiceDependency(containerName).setService(
                     IStatisticsManager.class).setCallbacks(
                     "setStatisticsManager", "unsetStatisticsManager")