Merge "Exception for URI /restconf/operations/module_name:rpc ended with slash"
authorTony Tkacik <ttkacik@cisco.com>
Thu, 27 Feb 2014 16:06:03 +0000 (16:06 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Thu, 27 Feb 2014 16:06:03 +0000 (16:06 +0000)
203 files changed:
opendaylight/commons/opendaylight/pom.xml
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractProtocolSession.java
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractSessionNegotiator.java
opendaylight/config/config-api/pom.xml
opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ConflictingVersionException.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/JmxAttribute.java
opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ModuleIdentifier.java
opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/ValidationException.java
opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/CommitStatus.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/java/org/opendaylight/controller/config/spi/Module.java
opendaylight/config/config-manager/pom.xml
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/CommitInfo.java
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/ConfigTransactionControllerInternal.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/DeadlockMonitor.java [new file with mode: 0644]
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ModuleInternalInfo.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/TransactionIdentifier.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/TransactionStatus.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 [moved from opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/DestroyedModule.java with 94% similarity]
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/ModuleInternalTransactionalInfo.java [moved from opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ModuleInternalTransactionalInfo.java with 72% similarity]
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/ModulesHolder.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/TransactionHolder.java [deleted file]
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/DynamicWritableWrapper.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/factoriesresolver/HierarchicalConfigMBeanFactoriesHolder.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/ServiceReference.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/jmx/TransactionJMXRegistrator.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/ConfigManagerActivator.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/mapping/ModuleInfoBundleTracker.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverManagerTest.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/TestingParallelAPSPModule.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/test/SimpleConfigurationTest.java
opendaylight/config/config-module-archetype/pom.xml
opendaylight/config/config-persister-api/pom.xml
opendaylight/config/config-persister-directory-adapter/pom.xml
opendaylight/config/config-persister-directory-autodetect-adapter/pom.xml
opendaylight/config/config-persister-directory-xml-adapter/pom.xml
opendaylight/config/config-persister-file-adapter/pom.xml
opendaylight/config/config-persister-file-xml-adapter/pom.xml
opendaylight/config/config-plugin-parent/pom.xml
opendaylight/config/config-util/pom.xml
opendaylight/config/config-util/src/main/java/org/opendaylight/controller/config/util/ConfigTransactionJMXClient.java
opendaylight/config/logback-config/pom.xml
opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackModuleWithInitialConfigurationTest.java
opendaylight/config/logback-config/src/test/java/org/opendaylight/controller/config/yang/logback/config/LogbackWithXmlConfigModuleTest.java
opendaylight/config/netty-config-api/pom.xml
opendaylight/config/netty-event-executor-config/pom.xml
opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/AutoCloseableEventExecutor.java [new file with mode: 0644]
opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/GlobalEventExecutorModule.java
opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/ImmediateEventExecutorModule.java [new file with mode: 0644]
opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/ImmediateEventExecutorModuleFactory.java [new file with mode: 0644]
opendaylight/config/netty-event-executor-config/src/main/yang/netty-event-executor.yang
opendaylight/config/netty-threadgroup-config/pom.xml
opendaylight/config/netty-timer-config/pom.xml
opendaylight/config/pom.xml
opendaylight/config/shutdown-api/pom.xml
opendaylight/config/shutdown-impl/pom.xml
opendaylight/config/shutdown-impl/src/test/java/org/opendaylight/controller/config/yang/shutdown/impl/ShutdownTest.java
opendaylight/config/threadpool-config-api/pom.xml
opendaylight/config/threadpool-config-impl/pom.xml
opendaylight/config/yang-jmx-generator-it/pom.xml
opendaylight/config/yang-jmx-generator-plugin/pom.xml
opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/ftl/FtlFilePersister.java
opendaylight/config/yang-jmx-generator/pom.xml
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/attribute/TOAttribute.java
opendaylight/config/yang-store-api/pom.xml
opendaylight/config/yang-store-impl/pom.xml
opendaylight/config/yang-test-plugin/pom.xml
opendaylight/config/yang-test/pom.xml
opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/IdentityTestModule.java
opendaylight/config/yang-test/src/main/java/org/opendaylight/controller/config/yang/test/impl/IdentityTestModuleStub.txt
opendaylight/distribution/opendaylight/src/main/resources/run.sh
opendaylight/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManager.java
opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowServiceAdapter.java
opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowStatisticsAdapter.java
opendaylight/md-sal/model/pom.xml
opendaylight/md-sal/pom.xml
opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/api/RoutingTable.java
opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/Activator.java
opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImpl.java
opendaylight/md-sal/remoterpc-routingtable/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImplTest.java
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataBrokerService.java
opendaylight/md-sal/sal-binding-broker/pom.xml
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerImpl.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DeprecatedDataAPISupport.xtend [deleted file]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java
opendaylight/md-sal/sal-binding-config/pom.xml
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/WriteParentReadChildTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-it/pom.xml
opendaylight/md-sal/sal-binding-util/src/main/java/org/opendaylight/controller/md/sal/binding/util/AbstractBindingSalConsumerInstance.java
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataCommitHandler.java
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/TwoPhaseCommit.java
opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/Futures.java
opendaylight/md-sal/sal-dom-api/pom.xml
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/Broker.java
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RoutedRpcDefaultImplementation.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcImplementation.java
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcProvisionRegistry.java
opendaylight/md-sal/sal-dom-broker/pom.xml
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/MountPointImpl.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareRpcBroker.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/RpcProvisionRegistryProxy.java
opendaylight/md-sal/sal-netconf-connector/pom.xml
opendaylight/md-sal/sal-remote/pom.xml
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/config/yang/md/sal/remote/rpc/ZeroMQServerModule.java
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/ClientImpl.java
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RemoteRpcClient.java
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RemoteRpcProvider.java
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/RoutingTableProvider.java
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/ServerImpl.java
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/dto/RouteIdentifierImpl.java
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/yang/odl-sal-dom-rpc-remote-cfg.yang
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/ClientImplTest.java
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/MockRoutingTable.java
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/RemoteRpcProviderTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/RouteIdentifierImplTest.java [deleted file]
opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/ServerImplTest.java
opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-nb/pom.xml
opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/binding/impl/DataBrokerServiceImpl.java
opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/client/SalRemoteClient.java [moved from opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/ToasterActivator.java with 55% similarity]
opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/client/SalRemoteClientDeployer.java [new file with mode: 0644]
opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/client/SalRemoteClientImpl.java [new file with mode: 0644]
opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/DataBrokerServiceImpl.java
opendaylight/md-sal/samples/pom.xml
opendaylight/md-sal/samples/toaster-consumer/pom.xml
opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/config/yang/config/toaster_consumer/impl/ToasterConsumerModule.java [new file with mode: 0644]
opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/config/yang/config/toaster_consumer/impl/ToasterConsumerModuleFactory.java [new file with mode: 0644]
opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/sample/toaster/provider/impl/ToastConsumerImpl.java
opendaylight/md-sal/samples/toaster-consumer/src/main/yang/toaster-consumer-impl.yang [new file with mode: 0644]
opendaylight/md-sal/samples/toaster-consumer/src/main/yang/toaster-consumer.yang [new file with mode: 0644]
opendaylight/md-sal/samples/toaster-it/pom.xml
opendaylight/md-sal/samples/toaster-it/src/test/java/org/opendaylight/controller/sample/toaster/it/ToasterTest.java
opendaylight/md-sal/samples/toaster-it/src/test/resources/controller.xml [new file with mode: 0644]
opendaylight/md-sal/samples/toaster-it/src/test/resources/logback.xml
opendaylight/md-sal/samples/toaster-provider/pom.xml
opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/config/yang/config/toaster_provider/impl/ToasterProviderModule.java [new file with mode: 0644]
opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/config/yang/config/toaster_provider/impl/ToasterProviderModuleFactory.java [new file with mode: 0644]
opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/OpendaylightToaster.java
opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/ToasterProvider.java [deleted file]
opendaylight/md-sal/samples/toaster-provider/src/main/yang/toaster-provider-impl.yang [new file with mode: 0644]
opendaylight/md-sal/samples/toaster-provider/src/main/yang/toaster-provider.yang [new file with mode: 0644]
opendaylight/md-sal/samples/toaster/pom.xml
opendaylight/netconf/config-netconf-connector/pom.xml
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/Commit.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/DiscardChanges.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/Validate.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfig.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/Activator.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/transactions/TransactionProvider.java
opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java
opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfigTest.java
opendaylight/netconf/config-persister-impl/pom.xml
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherConfiguration.java [new file with mode: 0644]
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherConfigurationBuilder.java [new file with mode: 0644]
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregator.java
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterActivator.java
opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterTest.java [new file with mode: 0644]
opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/MockNetconfEndpoint.java [new file with mode: 0644]
opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/MockedBundleContext.java [new file with mode: 0644]
opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/TestingExceptionHandler.java [new file with mode: 0644]
opendaylight/netconf/ietf-netconf-monitoring-extension/pom.xml
opendaylight/netconf/ietf-netconf-monitoring/pom.xml
opendaylight/netconf/netconf-api/pom.xml
opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfDocumentedException.java
opendaylight/netconf/netconf-client/pom.xml
opendaylight/netconf/netconf-impl/pom.xml
opendaylight/netconf/netconf-it/pom.xml
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/pax/IdentityRefNetconfTest.java [new file with mode: 0644]
opendaylight/netconf/netconf-it/src/test/resources/controller.xml [new file with mode: 0644]
opendaylight/netconf/netconf-it/src/test/resources/netconfMessages/commit.xml [new file with mode: 0644]
opendaylight/netconf/netconf-it/src/test/resources/netconfMessages/editConfig_identities.xml [new file with mode: 0644]
opendaylight/netconf/netconf-it/src/test/resources/netconfMessages/getConfig.xml [new file with mode: 0644]
opendaylight/netconf/netconf-mapping-api/pom.xml
opendaylight/netconf/netconf-monitoring/pom.xml
opendaylight/netconf/netconf-ssh/pom.xml
opendaylight/netconf/netconf-util/pom.xml
opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/test/XmlFileLoader.java
opendaylight/netconf/pom.xml
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFloatingIPsNorthbound.java
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronNetworksNorthbound.java
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronPortsNorthbound.java
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronRoutersNorthbound.java
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSubnetsNorthbound.java
opendaylight/sal/api/pom.xml
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Edge.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Path.java

index 328dfafe3f7a239c7e2f1846087ad8aee9a4bd10..d42f1fd83d9a45fa4b24a97bf2445f9519206740 100644 (file)
     <arphandler.version>0.5.2-SNAPSHOT</arphandler.version>
     <forwarding.staticrouting>0.5.2-SNAPSHOT</forwarding.staticrouting>
     <samples.loadbalancer>0.5.2-SNAPSHOT</samples.loadbalancer>
-    <config.version>0.2.4-SNAPSHOT</config.version>
-    <netconf.version>0.2.4-SNAPSHOT</netconf.version>
+    <config.version>0.2.5-SNAPSHOT</config.version>
+    <netconf.version>0.2.5-SNAPSHOT</netconf.version>
     <mdsal.version>1.1-SNAPSHOT</mdsal.version>
     <containermanager.version>0.5.2-SNAPSHOT</containermanager.version>
     <containermanager.it.version>0.5.2-SNAPSHOT</containermanager.it.version>
     <switchmanager.api.version>0.7.1-SNAPSHOT</switchmanager.api.version>
     <connectionmanager.version>0.1.2-SNAPSHOT</connectionmanager.version>
-    <sal.version>0.7.1-SNAPSHOT</sal.version>
+    <sal.version>0.8.1-SNAPSHOT</sal.version>
     <sal.networkconfiguration.version>0.0.3-SNAPSHOT</sal.networkconfiguration.version>
     <sal.connection.version>0.1.2-SNAPSHOT</sal.connection.version>
     <networkconfig.bridgedomain.northbound.version>0.0.3-SNAPSHOT</networkconfig.bridgedomain.northbound.version>
     <java.version.target>1.7</java.version.target>
     <!-- enforcer version -->
     <enforcer.version>1.3.1</enforcer.version>
+    <xtend.version>2.4.3</xtend.version>
+    <xtend.dstdir>${project.build.directory}/generated-sources/xtend-gen</xtend.dstdir>
   </properties>
 
   <dependencyManagement>
       </dependency>
 
         <!-- md-sal -->
+        <dependency>
+            <groupId>org.eclipse.xtend</groupId>
+            <artifactId>org.eclipse.xtend.lib</artifactId>
+            <version>${xtend.version}</version>
+        </dependency>
         <dependency>
           <groupId>org.opendaylight.controller</groupId>
           <artifactId>sal-common</artifactId>
           <artifactId>config-persister-impl</artifactId>
           <version>${netconf.version}</version>
         </dependency>
-        <dependency>
-          <groupId>${project.groupId}</groupId>
-          <artifactId>ietf-netconf-monitoring</artifactId>
-          <version>${netconf.version}</version>
-        </dependency>
-        <dependency>
-          <groupId>${project.groupId}</groupId>
-          <artifactId>ietf-netconf-monitoring-extension</artifactId>
-          <version>${netconf.version}</version>
-        </dependency>
 
          <!-- threadpool -->
           <dependency>
           <artifactId>maven-release-plugin</artifactId>
           <version>${releaseplugin.version}</version>
         </plugin>
+        <plugin>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-maven-plugin</artifactId>
+            <version>${yangtools.version}</version>
+        </plugin>
         <!-- Ignore/Execute plugin execution -->
         <plugin>
           <groupId>org.eclipse.m2e</groupId>
             <testTarget>${java.version.target}</testTarget>
           </configuration>
        </plugin>
+          <plugin>
+              <groupId>org.eclipse.xtend</groupId>
+              <artifactId>xtend-maven-plugin</artifactId>
+              <version>${xtend.version}</version>
+              <executions>
+                  <execution>
+                      <goals>
+                          <goal>compile</goal>
+                      </goals>
+                      <configuration>
+                          <outputDirectory>${xtend.dstdir}</outputDirectory>
+                      </configuration>
+                  </execution>
+              </executions>
+          </plugin>
       </plugins>
     </pluginManagement>
   </build>
index e7bd66574036111c72a0ddad5291afdd905e1ac7..47e96d1ff490df392accfb84dc10d55eb84a4583 100644 (file)
@@ -40,6 +40,7 @@ public abstract class AbstractProtocolSession<M> extends SimpleChannelInboundHan
     }
 
     @Override
+    @SuppressWarnings("unchecked")
     protected final void channelRead0(final ChannelHandlerContext ctx, final Object msg) {
         LOG.debug("Message was received: {}", msg);
         handleMessage((M) msg);
index d41e8106c5aec85166b43d72241b7fb600921801..cbe923524516077497f806fdad9b74c4d84e9927 100644 (file)
@@ -85,6 +85,7 @@ public abstract class AbstractSessionNegotiator<M, S extends AbstractProtocolSes
     }
 
     @Override
+    @SuppressWarnings("unchecked")
     public final void channelRead(final ChannelHandlerContext ctx, final Object msg) {
         LOG.debug("Negotiation read invoked on channel {}", channel);
         try {
index 425e4b4406b6ecaed86bcd501c1ab551e3d725ec..cab2e8c44e1584ba3962ac5f94d74461e1e9753a 100644 (file)
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>config-subsystem</artifactId>
         <groupId>org.opendaylight.controller</groupId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
     </parent>
 
     <artifactId>config-api</artifactId>
index 9c25242c2d08dd917a49af26f02c8def04080e67..2edf2614999776c32230d7f275d80430e692b31b 100644 (file)
@@ -14,7 +14,7 @@ package org.opendaylight.controller.config.api;
  * transaction was committed after creating this transaction. Clients can create
  * new transaction and merge the changes.
  */
-public class ConflictingVersionException extends RuntimeException {
+public class ConflictingVersionException extends Exception {
     private static final long serialVersionUID = 1L;
 
     public ConflictingVersionException() {
index 73737593cf6af9359660147a4fb44d145809f6b5..5ad6e0da8d2bf8a29d8d403783e378c5ab950346 100644 (file)
@@ -19,8 +19,9 @@ public final class IdentityAttributeRef {
 
     @ConstructorProperties(QNAME_ATTR_NAME)
     public IdentityAttributeRef(String qNameOfIdentity) {
-        if (qNameOfIdentity == null)
+        if (qNameOfIdentity == null) {
             throw new NullPointerException("Parameter " + QNAME_ATTR_NAME + " is null");
+        }
         this.qNameOfIdentity = qNameOfIdentity;
     }
 
@@ -46,12 +47,18 @@ public final class IdentityAttributeRef {
 
     @Override
     public boolean equals(Object o) {
-        if (this == o) return true;
-        if (!(o instanceof IdentityAttributeRef)) return false;
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof IdentityAttributeRef)) {
+            return false;
+        }
 
         IdentityAttributeRef that = (IdentityAttributeRef) o;
 
-        if (!qNameOfIdentity.equals(that.qNameOfIdentity)) return false;
+        if (!qNameOfIdentity.equals(that.qNameOfIdentity)) {
+            return false;
+        }
 
         return true;
     }
index 96deb051ef91a1f1f4a3d629fc7984626ddf0dc9..244f22f58efdd5b1615806a2859fd50902b79172 100644 (file)
@@ -15,8 +15,9 @@ public class JmxAttribute {
     private final String attributeName;
 
     public JmxAttribute(String attributeName) {
-        if (attributeName == null)
+        if (attributeName == null) {
             throw new NullPointerException("Parameter 'attributeName' is null");
+        }
         this.attributeName = attributeName;
     }
 
@@ -26,16 +27,19 @@ public class JmxAttribute {
 
     @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;
+        }
 
         JmxAttribute that = (JmxAttribute) o;
 
         if (attributeName != null ? !attributeName.equals(that.attributeName)
-                : that.attributeName != null)
+                : that.attributeName != null) {
             return false;
+        }
 
         return true;
     }
index c654f5fe0a3c97bacb0885df0857ca804db7939f..7baaf9f6e45021bb87dced0ee189fa889767e52d 100644 (file)
@@ -14,12 +14,12 @@ public class ModuleIdentifier implements Identifier {
     private final String factoryName, instanceName;
 
     public ModuleIdentifier(String factoryName, String instanceName) {
-        if (factoryName == null)
-            throw new IllegalArgumentException(
-                    "Parameter 'factoryName' is null");
-        if (instanceName == null)
-            throw new IllegalArgumentException(
-                    "Parameter 'instanceName' is null");
+        if (factoryName == null) {
+            throw new IllegalArgumentException("Parameter 'factoryName' is null");
+        }
+        if (instanceName == null) {
+            throw new IllegalArgumentException("Parameter 'instanceName' is null");
+        }
         this.factoryName = factoryName;
         this.instanceName = instanceName;
     }
@@ -34,17 +34,21 @@ public class ModuleIdentifier implements Identifier {
 
     @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;
+        }
 
         ModuleIdentifier that = (ModuleIdentifier) o;
 
-        if (!factoryName.equals(that.factoryName))
+        if (!factoryName.equals(that.factoryName)) {
             return false;
-        if (!instanceName.equals(that.instanceName))
+        }
+        if (!instanceName.equals(that.instanceName)) {
             return false;
+        }
 
         return true;
     }
index f27d12399528c38c144fc17ea0354c243365a1a6..82b73d419e402a31f85a4dfeba7266c26d86b802 100644 (file)
@@ -16,9 +16,11 @@ import java.util.Map.Entry;
 
 /**
  * This exception is not intended to be used while implementing modules,
- * itaggregates validation exceptions and sends them back to the user.
+ * it aggregates validation exceptions and sends them back to the user.
+ * Use {@link org.opendaylight.controller.config.api.JmxAttributeValidationException} for
+ * validating modules instead.
  */
-public class ValidationException extends RuntimeException {
+public class ValidationException extends Exception {
     private static final long serialVersionUID = -6072893219820274247L;
 
     private final Map<String/* module name */, Map<String/* instance name */, ExceptionMessageWithStackTrace>> failedValidations;
@@ -118,23 +120,30 @@ public class ValidationException extends RuntimeException {
 
         @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;
+            }
             ExceptionMessageWithStackTrace other = (ExceptionMessageWithStackTrace) obj;
             if (message == null) {
-                if (other.message != null)
+                if (other.message != null) {
                     return false;
-            } else if (!message.equals(other.message))
+                }
+            } else if (!message.equals(other.message)) {
                 return false;
+            }
             if (stackTrace == null) {
-                if (other.stackTrace != null)
+                if (other.stackTrace != null) {
                     return false;
-            } else if (!stackTrace.equals(other.stackTrace))
+                }
+            } else if (!stackTrace.equals(other.stackTrace)) {
                 return false;
+            }
             return true;
         }
 
index bd53bd4e581dc7285fcd8b874fbae177a8cc13c2..4f9ea7ac6b57521697f85ca7e4cde7930601ad1e 100644 (file)
@@ -7,32 +7,27 @@
  */
 package org.opendaylight.controller.config.api.jmx;
 
+import javax.annotation.concurrent.Immutable;
+import javax.management.ObjectName;
 import java.beans.ConstructorProperties;
 import java.util.Collections;
 import java.util.List;
 
-import javax.annotation.concurrent.Immutable;
-import javax.management.ObjectName;
-
 @Immutable
 public class CommitStatus {
     private final List<ObjectName> newInstances, reusedInstances,
             recreatedInstances;
 
     /**
-     *
-     * @param newInstances
-     *            newly created instances
-     * @param reusedInstances
-     *            reused instances
-     * @param recreatedInstances
-     *            recreated instances
+     * @param newInstances       newly created instances
+     * @param reusedInstances    reused instances
+     * @param recreatedInstances recreated instances
      */
-    @ConstructorProperties({ "newInstances", "reusedInstances",
-            "recreatedInstances" })
+    @ConstructorProperties({"newInstances", "reusedInstances",
+            "recreatedInstances"})
     public CommitStatus(List<ObjectName> newInstances,
-            List<ObjectName> reusedInstances,
-            List<ObjectName> recreatedInstances) {
+                        List<ObjectName> reusedInstances,
+                        List<ObjectName> recreatedInstances) {
         this.newInstances = Collections.unmodifiableList(newInstances);
         this.reusedInstances = Collections.unmodifiableList(reusedInstances);
         this.recreatedInstances = Collections
@@ -40,7 +35,6 @@ public class CommitStatus {
     }
 
     /**
-     *
      * @return list of objectNames representing newly created instances
      */
     public List<ObjectName> getNewInstances() {
@@ -48,7 +42,6 @@ public class CommitStatus {
     }
 
     /**
-     *
      * @return list of objectNames representing reused instances
      */
     public List<ObjectName> getReusedInstances() {
@@ -56,7 +49,6 @@ public class CommitStatus {
     }
 
     /**
-     *
      * @return list of objectNames representing recreated instances
      */
     public List<ObjectName> getRecreatedInstances() {
@@ -72,7 +64,7 @@ public class CommitStatus {
         result = prime
                 * result
                 + ((recreatedInstances == null) ? 0 : recreatedInstances
-                        .hashCode());
+                .hashCode());
         result = prime * result
                 + ((reusedInstances == null) ? 0 : reusedInstances.hashCode());
         return result;
@@ -80,28 +72,37 @@ public class CommitStatus {
 
     @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;
+        }
         CommitStatus other = (CommitStatus) obj;
         if (newInstances == null) {
-            if (other.newInstances != null)
+            if (other.newInstances != null) {
                 return false;
-        } else if (!newInstances.equals(other.newInstances))
+            }
+        } else if (!newInstances.equals(other.newInstances)) {
             return false;
+        }
         if (recreatedInstances == null) {
-            if (other.recreatedInstances != null)
+            if (other.recreatedInstances != null) {
                 return false;
-        } else if (!recreatedInstances.equals(other.recreatedInstances))
+            }
+        } else if (!recreatedInstances.equals(other.recreatedInstances)) {
             return false;
+        }
         if (reusedInstances == null) {
-            if (other.reusedInstances != null)
+            if (other.reusedInstances != null) {
                 return false;
-        } else if (!reusedInstances.equals(other.reusedInstances))
+            }
+        } else if (!reusedInstances.equals(other.reusedInstances)) {
             return false;
+        }
         return true;
     }
 
index 3baa1039e0bd1c868c28b6d8d5f7ea35c8da3dc7..d60e6086176daebd69f58a795ccadd4f24eca4de 100644 (file)
@@ -11,6 +11,7 @@ import org.opendaylight.controller.config.api.ModuleIdentifier;
 import org.opendaylight.controller.config.api.jmx.constants.ConfigRegistryConstants;
 
 import javax.annotation.concurrent.ThreadSafe;
+import javax.management.MalformedObjectNameException;
 import javax.management.ObjectName;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -46,8 +47,8 @@ public class ObjectNameUtil {
     public static ObjectName createON(String on) {
         try {
             return new ObjectName(on);
-        } catch (Exception e) {
-            throw new RuntimeException(e);
+        } catch (MalformedObjectNameException e) {
+            throw new IllegalArgumentException(e);
         }
     }
 
@@ -63,8 +64,8 @@ public class ObjectNameUtil {
         Hashtable<String, String> table = new Hashtable<>(attribs);
         try {
             return new ObjectName(domain, table);
-        } catch (Exception e) {
-            throw new RuntimeException(e);
+        } catch (MalformedObjectNameException e) {
+            throw new IllegalArgumentException(e);
         }
 
     }
@@ -116,8 +117,7 @@ public class ObjectNameUtil {
     public static String getServiceQName(ObjectName objectName) {
         checkType(objectName, TYPE_SERVICE_REFERENCE);
         String quoted = objectName.getKeyProperty(SERVICE_QNAME_KEY);
-        String result = unquoteAndUnescape(objectName, quoted);
-        return result;
+        return unquoteAndUnescape(objectName, quoted);
     }
 
     // ObjectName supports quotation and ignores tokens like =, but fails to ignore ? sign.
@@ -292,8 +292,8 @@ public class ObjectNameUtil {
         }
     }
 
-    public static void checkTypeOneOf(ObjectName objectName, String ... types) {
-        for(String type: types) {
+    public static void checkTypeOneOf(ObjectName objectName, String... types) {
+        for (String type : types) {
             if (type.equals(objectName.getKeyProperty(TYPE_KEY))) {
                 return;
             }
@@ -304,10 +304,12 @@ public class ObjectNameUtil {
 
     public static ObjectName createModulePattern(String moduleName,
                                                  String instanceName) {
-        if (moduleName == null)
+        if (moduleName == null) {
             moduleName = "*";
-        if (instanceName == null)
+        }
+        if (instanceName == null) {
             instanceName = "*";
+        }
         // do not return object names containing transaction name
         ObjectName namePattern = ObjectNameUtil
                 .createON(ObjectNameUtil.ON_DOMAIN + ":"
@@ -343,13 +345,15 @@ public class ObjectNameUtil {
                                           String expectedType) {
         checkType(objectName, expectedType);
         String factoryName = getFactoryName(objectName);
-        if (factoryName == null)
+        if (factoryName == null) {
             throw new IllegalArgumentException(
                     "ObjectName does not contain module name");
+        }
         String instanceName = getInstanceName(objectName);
-        if (instanceName == null)
+        if (instanceName == null) {
             throw new IllegalArgumentException(
                     "ObjectName does not contain instance name");
+        }
         return new ModuleIdentifier(factoryName, instanceName);
     }
 
index 81a29bf7b3198215bcba9eb5a92732df3238f77d..1d9563bf4e1d7733b170cdd6c092f473a8baae20 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.controller.config.api.jmx.constants;
 
+import javax.management.MalformedObjectNameException;
 import javax.management.ObjectName;
 
 public class ConfigRegistryConstants {
@@ -19,7 +20,7 @@ public class ConfigRegistryConstants {
 
     public static final ObjectName OBJECT_NAME = createONWithDomainAndType(TYPE_CONFIG_REGISTRY);
 
-    public static String GET_AVAILABLE_MODULE_NAMES_ATTRIBUT_NAME = "AvailableModuleNames";
+    public static final String GET_AVAILABLE_MODULE_NAMES_ATTRIBUT_NAME = "AvailableModuleNames";
 
     public static ObjectName createONWithDomainAndType(String type) {
         return createON(ON_DOMAIN, TYPE_KEY, type);
@@ -28,8 +29,8 @@ public class ConfigRegistryConstants {
     public static ObjectName createON(String name, String key, String value) {
         try {
             return new ObjectName(name, key, value);
-        } catch (Exception e) {
-            throw new RuntimeException(e);
+        } catch (MalformedObjectNameException e) {
+            throw new IllegalArgumentException(e);
         }
 
     }
index dd11b7503f0e09d8af7710cf89bd6ccdaab0ec74..1b16ec828432624b120228c4cacfd91479a0406e 100644 (file)
@@ -7,11 +7,11 @@
  */
 package org.opendaylight.controller.config.spi;
 
-import javax.annotation.concurrent.NotThreadSafe;
-
 import org.opendaylight.controller.config.api.ModuleIdentifier;
 import org.opendaylight.yangtools.concepts.Identifiable;
 
+import javax.annotation.concurrent.NotThreadSafe;
+
 
 /**
  * Represents one service that is to be configured. These methods need to be
@@ -20,7 +20,7 @@ import org.opendaylight.yangtools.concepts.Identifiable;
  * ConfigBeans.
  * <p>
  * In order to guide dependency resolution, the setter method should be
- * annotated with {@link RequireInterface}.
+ * annotated with {@link org.opendaylight.controller.config.api.annotations.RequireInterface}.
  * </p>
  * <p>
  * Thread safety note: implementations of this interface are not required to be
@@ -43,10 +43,10 @@ public interface Module extends Identifiable<ModuleIdentifier>{
      * Returns 'live' object that was configured using this object. It is
      * allowed to call this method only after all ConfigBeans were validated. In
      * this method new resources might be opened or old instance might be
-     * modified. Note that when obtaining dependent Module using
-     * {@link org.opendaylight.controller.config.api.DependencyResolver#validateDependency(Class, javax.management.ObjectName, String)}
-     * a proxy will be created that will disallow calling this method before
-     * second commit phase begins.
+     * modified. This method must be implemented so that it returns same
+     * result for a single transaction. Since Module is created per transaction
+     * this means that it must be safe to cache result of first call.
+     *
      *
      * @return closeable instance: After bundle update the factory might be able
      *         to copy old configuration into new one without being able to cast
index 524cd1ff9ec12e8d051055df2e9b7cb3dc620426..7d7d9d697adb8de75638d8604eae81f28c35a481 100644 (file)
@@ -3,7 +3,7 @@
     <parent>
         <artifactId>config-subsystem</artifactId>
         <groupId>org.opendaylight.controller</groupId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
         <relativePath>..</relativePath>
     </parent>
     <artifactId>config-manager</artifactId>
@@ -68,7 +68,6 @@
         <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
-            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.opendaylight.yangtools</groupId>
index 9d086295e3c30fc9b5524357b8e0c1ca3dc96d0a..28732d8f68ea6e53832e954ff388681c608bc26b 100644 (file)
@@ -14,6 +14,8 @@ import java.util.Map;
 import javax.annotation.concurrent.Immutable;
 
 import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.DestroyedModule;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.ModuleInternalTransactionalInfo;
 
 /**
  * Structure obtained during first phase commit, contains destroyed modules from
index 39682fa6b470226400b47a6aa0fdbec24a4bf522..dd510a1ed7099a3e087e7e4aa935b0881d6f84fb 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.controller.config.manager.impl;
 
+import com.google.common.collect.Maps;
 import org.opendaylight.controller.config.api.ConflictingVersionException;
 import org.opendaylight.controller.config.api.ModuleIdentifier;
 import org.opendaylight.controller.config.api.RuntimeBeanRegistratorAwareModule;
@@ -14,6 +15,8 @@ import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry;
 import org.opendaylight.controller.config.api.ValidationException;
 import org.opendaylight.controller.config.api.jmx.CommitStatus;
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.DestroyedModule;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.ModuleInternalTransactionalInfo;
 import org.opendaylight.controller.config.manager.impl.dynamicmbean.DynamicReadableWrapper;
 import org.opendaylight.controller.config.manager.impl.factoriesresolver.HierarchicalConfigMBeanFactoriesHolder;
 import org.opendaylight.controller.config.manager.impl.factoriesresolver.ModuleFactoriesResolver;
@@ -105,19 +108,19 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
     private List<ModuleFactory> lastListOfFactories = Collections.emptyList();
 
     @GuardedBy("this") // switched in every 2ndPC
-    private CloseableServiceReferenceReadableRegistry  readableSRRegistry = ServiceReferenceRegistryImpl.createInitialSRLookupRegistry();
+    private CloseableServiceReferenceReadableRegistry readableSRRegistry = ServiceReferenceRegistryImpl.createInitialSRLookupRegistry();
 
     // constructor
     public ConfigRegistryImpl(ModuleFactoriesResolver resolver,
-            MBeanServer configMBeanServer, CodecRegistry codecRegistry) {
+                              MBeanServer configMBeanServer, CodecRegistry codecRegistry) {
         this(resolver, configMBeanServer,
                 new BaseJMXRegistrator(configMBeanServer), codecRegistry);
     }
 
     // constructor
     public ConfigRegistryImpl(ModuleFactoriesResolver resolver,
-            MBeanServer configMBeanServer,
-            BaseJMXRegistrator baseJMXRegistrator, CodecRegistry codecRegistry) {
+                              MBeanServer configMBeanServer,
+                              BaseJMXRegistrator baseJMXRegistrator, CodecRegistry codecRegistry) {
         this.resolver = resolver;
         this.beanToOsgiServiceManager = new BeanToOsgiServiceManager();
         this.configMBeanServer = configMBeanServer;
@@ -173,7 +176,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
             throw new IllegalStateException(e);
         }
         transactionController.copyExistingModulesAndProcessFactoryDiff(currentConfig.getEntries(), lastListOfFactories);
-        transactionsHolder.add(transactionName, transactionController);
+        transactionsHolder.add(transactionName, transactionController, txLookupRegistry);
         return transactionController;
     }
 
@@ -181,6 +184,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
      * {@inheritDoc}
      */
     @Override
+    @SuppressWarnings("PMD.AvoidCatchingThrowable")
     public synchronized CommitStatus commitConfig(ObjectName transactionControllerON)
             throws ConflictingVersionException, ValidationException {
         final String transactionName = ObjectNameUtil
@@ -188,12 +192,13 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
         logger.trace("About to commit {}. Current parentVersion: {}, versionCounter {}", transactionName, version, versionCounter);
 
         // find ConfigTransactionController
-        Map<String, ConfigTransactionControllerInternal> transactions = transactionsHolder.getCurrentTransactions();
-        ConfigTransactionControllerInternal configTransactionController = transactions.get(transactionName);
-        if (configTransactionController == null) {
+        Map<String, Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>> transactions = transactionsHolder.getCurrentTransactions();
+        Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry> configTransactionControllerEntry = transactions.get(transactionName);
+        if (configTransactionControllerEntry == null) {
             throw new IllegalArgumentException(String.format(
                     "Transaction with name '%s' not found", transactionName));
         }
+        ConfigTransactionControllerInternal configTransactionController = configTransactionControllerEntry.getKey();
         // check optimistic lock
         if (version != configTransactionController.getParentVersion()) {
             throw new ConflictingVersionException(
@@ -208,10 +213,9 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
         lastListOfFactories = Collections.unmodifiableList(configTransactionController.getCurrentlyRegisteredFactories());
         // non recoverable from here:
         try {
-            return secondPhaseCommit(
-                    configTransactionController, commitInfo);
+            return secondPhaseCommit(configTransactionController, commitInfo, configTransactionControllerEntry.getValue());
         } catch (Throwable t) { // some libs throw Errors: e.g.
-                                // javax.xml.ws.spi.FactoryFinder$ConfigurationError
+            // javax.xml.ws.spi.FactoryFinder$ConfigurationError
             isHealthy = false;
             logger.error("Configuration Transaction failed on 2PC, server is unhealthy", t);
             if (t instanceof RuntimeException) {
@@ -225,14 +229,14 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
     }
 
     private CommitStatus secondPhaseCommit(ConfigTransactionControllerInternal configTransactionController,
-                                           CommitInfo commitInfo) {
+                                           CommitInfo commitInfo, ConfigTransactionLookupRegistry txLookupRegistry) {
 
         // close instances which were destroyed by the user, including
         // (hopefully) runtime beans
         for (DestroyedModule toBeDestroyed : commitInfo
                 .getDestroyedFromPreviousTransactions()) {
             toBeDestroyed.close(); // closes instance (which should close
-                                   // runtime jmx registrator),
+            // runtime jmx registrator),
             // also closes osgi registration and ModuleJMXRegistrator
             // registration
             currentConfig.remove(toBeDestroyed.getIdentifier());
@@ -254,7 +258,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
                         .getRuntimeBeanRegistrator();
             }
             // set runtime jmx registrator if required
-            Module module = entry.getModule();
+            Module module = entry.getProxiedModule();
             if (module instanceof RuntimeBeanRegistratorAwareModule) {
                 ((RuntimeBeanRegistratorAwareModule) module)
                         .setRuntimeBeanRegistrator(runtimeBeanRegistrator);
@@ -264,8 +268,9 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
         }
 
         // can register runtime beans
-        List<ModuleIdentifier> orderedModuleIdentifiers = configTransactionController
-                .secondPhaseCommit();
+        List<ModuleIdentifier> orderedModuleIdentifiers = configTransactionController.secondPhaseCommit();
+        txLookupRegistry.close();
+        configTransactionController.close();
 
         // copy configuration to read only mode
         List<ObjectName> newInstances = new LinkedList<>();
@@ -278,10 +283,11 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
         for (ModuleIdentifier moduleIdentifier : orderedModuleIdentifiers) {
             ModuleInternalTransactionalInfo entry = commitInfo.getCommitted()
                     .get(moduleIdentifier);
-            if (entry == null)
+            if (entry == null) {
                 throw new NullPointerException("Module not found "
                         + moduleIdentifier);
-            Module module = entry.getModule();
+            }
+
             ObjectName primaryReadOnlyON = ObjectNameUtil
                     .createReadOnlyModuleON(moduleIdentifier);
 
@@ -298,13 +304,14 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
                     .createModuleJMXRegistrator();
 
             OsgiRegistration osgiRegistration = null;
+            AutoCloseable instance = entry.getProxiedModule().getInstance();
             if (entry.hasOldModule()) {
                 ModuleInternalInfo oldInternalInfo = entry.getOldInternalInfo();
                 DynamicReadableWrapper oldReadableConfigBean = oldInternalInfo.getReadableModule();
                 currentConfig.remove(entry.getIdentifier());
 
                 // test if old instance == new instance
-                if (oldReadableConfigBean.getInstance().equals(module.getInstance())) {
+                if (oldReadableConfigBean.getInstance().equals(instance)) {
                     // reused old instance:
                     // wrap in readable dynamic mbean
                     reusedInstances.add(primaryReadOnlyON);
@@ -326,9 +333,10 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
                 // wrap in readable dynamic mbean
                 newInstances.add(primaryReadOnlyON);
             }
+            Module realModule = entry.getRealModule();
 
             DynamicReadableWrapper newReadableConfigBean = new DynamicReadableWrapper(
-                    module, module.getInstance(), moduleIdentifier,
+                    realModule, instance, moduleIdentifier,
                     registryMBeanServer, configMBeanServer);
 
             // register to JMX
@@ -342,10 +350,10 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
             // register to OSGi
             if (osgiRegistration == null) {
                 ModuleFactory moduleFactory = entry.getModuleFactory();
-                if(moduleFactory != null) {
+                if (moduleFactory != null) {
                     BundleContext bc = configTransactionController.
                             getModuleFactoryBundleContext(moduleFactory.getImplementationName());
-                    osgiRegistration = beanToOsgiServiceManager.registerToOsgi(module.getClass(),
+                    osgiRegistration = beanToOsgiServiceManager.registerToOsgi(realModule.getClass(),
                             newReadableConfigBean.getInstance(), entry.getIdentifier(), bc);
                 } else {
                     throw new NullPointerException(entry.getIdentifier().getFactoryName() + " ModuleFactory not found.");
@@ -360,7 +368,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
                     runtimeBeanRegistrator, newModuleJMXRegistrator,
                     orderingIdx, entry.isDefaultBean());
 
-            newConfigEntries.put(module, newInfo);
+            newConfigEntries.put(realModule, newInfo);
             orderingIdx++;
         }
         currentConfig.addAll(newConfigEntries.values());
@@ -382,12 +390,12 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
      */
     @Override
     public synchronized List<ObjectName> getOpenConfigs() {
-        Map<String, ConfigTransactionControllerInternal> transactions = transactionsHolder
+        Map<String, Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>> transactions = transactionsHolder
                 .getCurrentTransactions();
         List<ObjectName> result = new ArrayList<>(transactions.size());
-        for (ConfigTransactionControllerInternal configTransactionController : transactions
+        for (Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry> configTransactionControllerEntry : transactions
                 .values()) {
-            result.add(configTransactionController.getControllerObjectName());
+            result.add(configTransactionControllerEntry.getKey().getControllerObjectName());
         }
         return result;
     }
@@ -401,11 +409,14 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
     @Override
     public synchronized void close() {
         // abort transactions
-        Map<String, ConfigTransactionControllerInternal> transactions = transactionsHolder
+        Map<String, Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>> transactions = transactionsHolder
                 .getCurrentTransactions();
-        for (ConfigTransactionControllerInternal configTransactionController : transactions
+        for (Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry> configTransactionControllerEntry : transactions
                 .values()) {
+
+            ConfigTransactionControllerInternal configTransactionController = configTransactionControllerEntry.getKey();
             try {
+                configTransactionControllerEntry.getValue().close();
                 configTransactionController.abortConfig();
             } catch (RuntimeException e) {
                 logger.warn("Ignoring exception while aborting {}",
@@ -485,7 +496,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
      */
     @Override
     public Set<ObjectName> lookupConfigBeans(String moduleName,
-            String instanceName) {
+                                             String instanceName) {
         ObjectName namePattern = ObjectNameUtil.createModulePattern(moduleName,
                 instanceName);
         return baseJMXRegistrator.queryNames(namePattern, null);
@@ -504,11 +515,13 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
      */
     @Override
     public Set<ObjectName> lookupRuntimeBeans(String moduleName,
-            String instanceName) {
-        if (moduleName == null)
+                                              String instanceName) {
+        if (moduleName == null) {
             moduleName = "*";
-        if (instanceName == null)
+        }
+        if (instanceName == null) {
             instanceName = "*";
+        }
         ObjectName namePattern = ObjectNameUtil.createRuntimeBeanPattern(
                 moduleName, instanceName);
         return baseJMXRegistrator.queryNames(namePattern, null);
@@ -646,18 +659,18 @@ class TransactionsHolder {
      * {@link ConfigTransactionControllerInternal} instances, because platform
      * MBeanServer transforms mbeans into another representation. Map is cleaned
      * every time current transactions are requested.
-     *
      */
     @GuardedBy("ConfigRegistryImpl.this")
-    private final Map<String /* transactionName */, ConfigTransactionControllerInternal> transactions = new HashMap<>();
+    private final Map<String /* transactionName */,
+            Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>> transactions = new HashMap<>();
 
     /**
      * Can only be called from within synchronized method.
      */
     public void add(String transactionName,
-            ConfigTransactionControllerInternal transactionController) {
+                    ConfigTransactionControllerInternal transactionController, ConfigTransactionLookupRegistry txLookupRegistry) {
         Object oldValue = transactions.put(transactionName,
-                transactionController);
+                Maps.immutableEntry(transactionController, txLookupRegistry));
         if (oldValue != null) {
             throw new IllegalStateException(
                     "Error: two transactions with same name");
@@ -671,13 +684,13 @@ class TransactionsHolder {
      *
      * @return current view on transactions map.
      */
-    public Map<String, ConfigTransactionControllerInternal> getCurrentTransactions() {
+    public Map<String, Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>> getCurrentTransactions() {
         // first, remove closed transaction
-        for (Iterator<Entry<String, ConfigTransactionControllerInternal>> it = transactions
-                .entrySet().iterator(); it.hasNext();) {
-            Entry<String, ConfigTransactionControllerInternal> entry = it
+        for (Iterator<Entry<String, Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>>> it = transactions
+                .entrySet().iterator(); it.hasNext(); ) {
+            Entry<String, Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>> entry = it
                     .next();
-            if (entry.getValue().isClosed()) {
+            if (entry.getValue().getKey().isClosed()) {
                 it.remove();
             }
         }
index 0ec6969802438b2c8e71856bf64cdeeb7fbcfb74..84f76c993692055899f7aea55a477c44c970f576 100644 (file)
@@ -13,6 +13,7 @@ import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry;
 import org.opendaylight.controller.config.api.ValidationException;
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
 import org.opendaylight.controller.config.manager.impl.dependencyresolver.DependencyResolverManager;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.ModuleInternalTransactionalInfo;
 import org.opendaylight.controller.config.manager.impl.dynamicmbean.DynamicWritableWrapper;
 import org.opendaylight.controller.config.manager.impl.dynamicmbean.ReadOnlyAtomicBoolean;
 import org.opendaylight.controller.config.manager.impl.dynamicmbean.ReadOnlyAtomicBoolean.ReadOnlyAtomicBooleanImpl;
@@ -53,7 +54,7 @@ import static java.lang.String.format;
 class ConfigTransactionControllerImpl implements
         ConfigTransactionControllerInternal,
         ConfigTransactionControllerImplMXBean,
-        Identifiable<TransactionIdentifier>{
+        Identifiable<TransactionIdentifier> {
     private static final Logger logger = LoggerFactory.getLogger(ConfigTransactionControllerImpl.class);
 
     private final ConfigTransactionLookupRegistry txLookupRegistry;
@@ -95,7 +96,8 @@ class ConfigTransactionControllerImpl implements
         this.currentlyRegisteredFactories = currentlyRegisteredFactories;
         this.factoriesHolder = new HierarchicalConfigMBeanFactoriesHolder(currentlyRegisteredFactories);
         this.transactionStatus = new TransactionStatus();
-        this.dependencyResolverManager = new DependencyResolverManager(transactionName, transactionStatus, writableSRRegistry, codecRegistry);
+        this.dependencyResolverManager = new DependencyResolverManager(txLookupRegistry.getTransactionIdentifier(),
+                transactionStatus, writableSRRegistry, codecRegistry);
         this.transactionsMBeanServer = transactionsMBeanServer;
         this.configMBeanServer = configMBeanServer;
         this.blankTransaction = blankTransaction;
@@ -124,12 +126,12 @@ class ConfigTransactionControllerImpl implements
 
         List<ModuleFactory> toBeAdded = new ArrayList<>();
         List<ModuleFactory> toBeRemoved = new ArrayList<>();
-        for(ModuleFactory moduleFactory: factoriesHolder.getModuleFactories()) {
-            if (oldSet.contains(moduleFactory) == false){
+        for (ModuleFactory moduleFactory : factoriesHolder.getModuleFactories()) {
+            if (oldSet.contains(moduleFactory) == false) {
                 toBeAdded.add(moduleFactory);
             }
         }
-        for(ModuleFactory moduleFactory: lastListOfFactories){
+        for (ModuleFactory moduleFactory : lastListOfFactories) {
             if (newSet.contains(moduleFactory) == false) {
                 toBeRemoved.add(moduleFactory);
             }
@@ -151,7 +153,7 @@ class ConfigTransactionControllerImpl implements
         }
 
         // remove modules belonging to removed factories
-        for(ModuleFactory removedFactory: toBeRemoved){
+        for (ModuleFactory removedFactory : toBeRemoved) {
             List<ModuleIdentifier> modulesOfRemovedFactory = dependencyResolverManager.findAllByFactory(removedFactory);
             for (ModuleIdentifier name : modulesOfRemovedFactory) {
                 destroyModule(name);
@@ -189,7 +191,7 @@ class ConfigTransactionControllerImpl implements
 
     @Override
     public synchronized ObjectName createModule(String factoryName,
-            String instanceName) throws InstanceAlreadyExistsException {
+                                                String instanceName) throws InstanceAlreadyExistsException {
 
         transactionStatus.checkNotCommitStarted();
         transactionStatus.checkNotAborted();
@@ -213,11 +215,11 @@ class ConfigTransactionControllerImpl implements
             throws InstanceAlreadyExistsException {
 
         logger.debug("Adding module {} to transaction {}", moduleIdentifier, this);
-        if (moduleIdentifier.equals(module.getIdentifier())==false) {
+        if (moduleIdentifier.equals(module.getIdentifier()) == false) {
             throw new IllegalStateException("Incorrect name reported by module. Expected "
-             + moduleIdentifier + ", got " + module.getIdentifier());
+                    + moduleIdentifier + ", got " + module.getIdentifier());
         }
-        if (dependencyResolver.getIdentifier().equals(moduleIdentifier) == false ) {
+        if (dependencyResolver.getIdentifier().equals(moduleIdentifier) == false) {
             throw new IllegalStateException("Incorrect name reported by dependency resolver. Expected "
                     + moduleIdentifier + ", got " + dependencyResolver.getIdentifier());
         }
@@ -231,11 +233,10 @@ class ConfigTransactionControllerImpl implements
         // put wrapper to jmx
         TransactionModuleJMXRegistration transactionModuleJMXRegistration = getTxModuleJMXRegistrator()
                 .registerMBean(writableDynamicWrapper, writableON);
-        ModuleInternalTransactionalInfo moduleInternalTransactionalInfo = new ModuleInternalTransactionalInfo(
+
+        dependencyResolverManager.put(
                 moduleIdentifier, module, moduleFactory,
                 maybeOldConfigBeanInfo, transactionModuleJMXRegistration, isDefaultBean);
-
-        dependencyResolverManager.put(moduleInternalTransactionalInfo);
         return writableON;
     }
 
@@ -271,7 +272,7 @@ class ConfigTransactionControllerImpl implements
         // first remove refNames, it checks for objectname existence
         try {
             writableSRRegistry.removeServiceReferences(
-                    ObjectNameUtil.createTransactionModuleON(getTransactionName(),moduleIdentifier));
+                    ObjectNameUtil.createTransactionModuleON(getTransactionName(), moduleIdentifier));
         } catch (InstanceNotFoundException e) {
             logger.error("Possible code error: cannot find {} in {}", moduleIdentifier, writableSRRegistry);
             throw new IllegalStateException("Possible code error: cannot find " + moduleIdentifier, e);
@@ -294,8 +295,9 @@ class ConfigTransactionControllerImpl implements
 
     @Override
     public synchronized void validateConfig() throws ValidationException {
-        if (configBeanModificationDisabled.get())
+        if (configBeanModificationDisabled.get()) {
             throw new IllegalStateException("Cannot start validation");
+        }
         configBeanModificationDisabled.set(true);
         try {
             validate_noLocks();
@@ -383,7 +385,7 @@ class ConfigTransactionControllerImpl implements
                 logger.error("Commit failed on {} in transaction {}", name,
                         getTransactionIdentifier(), e);
                 internalAbort();
-                throw new RuntimeException(
+                throw new IllegalStateException(
                         format("Error - getInstance() failed for %s in transaction %s",
                                 name, getTransactionIdentifier()), e);
             }
@@ -393,8 +395,6 @@ class ConfigTransactionControllerImpl implements
 
         logger.trace("Committed configuration {}", getTransactionIdentifier());
         transactionStatus.setCommitted();
-        // unregister this and all modules from jmx
-        close();
 
         return dependencyResolverManager.getSortedModuleIdentifiers();
     }
@@ -412,8 +412,7 @@ class ConfigTransactionControllerImpl implements
     }
 
     public void close() {
-        //FIXME: should not close object that was retrieved in constructor, a wrapper object should do that perhaps
-        txLookupRegistry.close();
+        dependencyResolverManager.close();
     }
 
     @Override
@@ -571,6 +570,7 @@ class ConfigTransactionControllerImpl implements
         return writableSRRegistry;
     }
 
+    @Override
     public TransactionIdentifier getTransactionIdentifier() {
         return txLookupRegistry.getTransactionIdentifier();
     }
index 82bae44a01b60148b9105e4e8ef98cc1530daf9f..f6164e32561d7ad5688abde93ac6cb4bc96cbec1 100644 (file)
@@ -23,7 +23,7 @@ import org.osgi.framework.BundleContext;
  * and {@link ConfigRegistryImpl} (consumer).
  */
 interface ConfigTransactionControllerInternal extends
-        ConfigTransactionControllerImplMXBean {
+        ConfigTransactionControllerImplMXBean, AutoCloseable {
 
 
 
@@ -75,4 +75,8 @@ interface ConfigTransactionControllerInternal extends
 
     ServiceReferenceWritableRegistry getWritableRegistry();
 
+    TransactionIdentifier getTransactionIdentifier();
+
+    @Override
+    void close();
 }
diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/DeadlockMonitor.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/DeadlockMonitor.java
new file mode 100644 (file)
index 0000000..ba7ab7f
--- /dev/null
@@ -0,0 +1,122 @@
+package org.opendaylight.controller.config.manager.impl;
+
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.GuardedBy;
+import java.util.concurrent.TimeUnit;
+
+public class DeadlockMonitor implements AutoCloseable {
+    private static final Logger logger = LoggerFactory.getLogger(DeadlockMonitorRunnable.class);
+
+    private static final long WARN_AFTER_MILLIS = 5000;
+
+    private final TransactionIdentifier transactionIdentifier;
+    private final DeadlockMonitorRunnable thread;
+    @GuardedBy("this")
+    private ModuleIdentifierWithNanos moduleIdentifierWithNanos = new ModuleIdentifierWithNanos();
+
+    public DeadlockMonitor(TransactionIdentifier transactionIdentifier) {
+        this.transactionIdentifier = transactionIdentifier;
+        thread = new DeadlockMonitorRunnable();
+        thread.start();
+    }
+
+    public synchronized void setCurrentlyInstantiatedModule(ModuleIdentifier currentlyInstantiatedModule) {
+        this.moduleIdentifierWithNanos = new ModuleIdentifierWithNanos(currentlyInstantiatedModule);
+    }
+
+    public boolean isAlive() {
+        return thread.isAlive();
+    }
+
+    @Override
+    public void close() {
+        thread.interrupt();
+    }
+
+    @Override
+    public String toString() {
+        return "DeadlockMonitor{" + transactionIdentifier + '}';
+    }
+
+    private class DeadlockMonitorRunnable extends Thread {
+
+        private DeadlockMonitorRunnable() {
+            super(DeadlockMonitor.this.toString());
+        }
+
+        @Override
+        public void run() {
+            ModuleIdentifierWithNanos old = new ModuleIdentifierWithNanos(); // null moduleId
+            while (this.isInterrupted() == false) {
+                ModuleIdentifierWithNanos copy = new ModuleIdentifierWithNanos(DeadlockMonitor.this.moduleIdentifierWithNanos);
+                if (old.moduleIdentifier == null) {
+                    // started
+                    old = copy;
+                } else if (old.moduleIdentifier != null && old.equals(copy)) {
+                    // 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);
+                    }
+                }
+                try {
+                    sleep(1000);
+                } catch (InterruptedException e) {
+                    interrupt();
+                }
+            }
+            logger.trace("Exiting {}", this);
+        }
+
+        @Override
+        public String toString() {
+            return "DeadLockMonitorRunnable{" + transactionIdentifier + "}";
+        }
+    }
+
+    private class ModuleIdentifierWithNanos {
+        @Nullable
+        private final ModuleIdentifier moduleIdentifier;
+        private final long nanoTime;
+
+        private ModuleIdentifierWithNanos() {
+            moduleIdentifier = null;
+            nanoTime = System.nanoTime();
+        }
+
+        private ModuleIdentifierWithNanos(ModuleIdentifier moduleIdentifier) {
+            this.moduleIdentifier = moduleIdentifier;
+            nanoTime = System.nanoTime();
+        }
+
+        private ModuleIdentifierWithNanos(ModuleIdentifierWithNanos copy) {
+            moduleIdentifier = copy.moduleIdentifier;
+            nanoTime = copy.nanoTime;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            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)
+                return false;
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = moduleIdentifier != null ? moduleIdentifier.hashCode() : 0;
+            result = 31 * result + (int) (nanoTime ^ (nanoTime >>> 32));
+            return result;
+        }
+    }
+}
index 941aec10969fd90c700d257579b02c88520e40e9..fd6262cb8cf34f222b70c0e643bf9edc688d46b5 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.controller.config.manager.impl;
 import javax.annotation.Nullable;
 
 import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.DestroyedModule;
 import org.opendaylight.controller.config.manager.impl.dynamicmbean.DynamicReadableWrapper;
 import org.opendaylight.controller.config.manager.impl.jmx.ModuleJMXRegistrator;
 import org.opendaylight.controller.config.manager.impl.jmx.RootRuntimeBeanRegistratorImpl;
index 0faa32b7dc4e181962802d8d5e1345472d8378d9..bf35fd1ed86f6b8249dcb4a7ca386d85ad2a53d1 100644 (file)
@@ -195,7 +195,7 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe
 
         this.serviceReferenceRegistrator = serviceReferenceRegistratorFactory.create();
 
-        Map<String, Set<String /* QName */>> factoryNamesToQNames = new HashMap<>();
+        Map<String, Set<String /* QName */>> modifiableFactoryNamesToQNames = new HashMap<>();
         Set<ServiceInterfaceAnnotation> allAnnotations = new HashSet<>();
         Set<String /* qName */> allQNames = new HashSet<>();
         for (Entry<String, ModuleFactory> entry : factories.entrySet()) {
@@ -210,27 +210,27 @@ public class ServiceReferenceRegistryImpl implements CloseableServiceReferenceRe
             }
             allAnnotations.addAll(siAnnotations);
             allQNames.addAll(qNames);
-            factoryNamesToQNames.put(entry.getKey(), Collections.unmodifiableSet(qNames));
+            modifiableFactoryNamesToQNames.put(entry.getKey(), Collections.unmodifiableSet(qNames));
         }
-        this.factoryNamesToQNames = Collections.unmodifiableMap(factoryNamesToQNames);
+        this.factoryNamesToQNames = Collections.unmodifiableMap(modifiableFactoryNamesToQNames);
         this.allQNames = Collections.unmodifiableSet(allQNames);
         // fill namespacesToAnnotations
-        Map<String /* namespace */, Map<String /* localName */, ServiceInterfaceAnnotation>> namespacesToAnnotations =
+        Map<String /* namespace */, Map<String /* localName */, ServiceInterfaceAnnotation>> modifiableNamespacesToAnnotations =
                 new HashMap<>();
         for (ServiceInterfaceAnnotation sia : allAnnotations) {
-            Map<String, ServiceInterfaceAnnotation> ofNamespace = namespacesToAnnotations.get(sia.namespace());
+            Map<String, ServiceInterfaceAnnotation> ofNamespace = modifiableNamespacesToAnnotations.get(sia.namespace());
             if (ofNamespace == null) {
                 ofNamespace = new HashMap<>();
-                namespacesToAnnotations.put(sia.namespace(), ofNamespace);
+                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 {}",
-                        sia.namespace(), sia.localName(), namespacesToAnnotations);
+                        sia.namespace(), sia.localName(), modifiableNamespacesToAnnotations);
                 throw new IllegalArgumentException("Conflict between local names in " + sia.namespace() + " : " + sia.localName());
             }
             ofNamespace.put(sia.localName(), sia);
         }
-        this.namespacesToAnnotations = Collections.unmodifiableMap(namespacesToAnnotations);
+        this.namespacesToAnnotations = Collections.unmodifiableMap(modifiableNamespacesToAnnotations);
         // copy refNames
         logger.trace("factoryNamesToQNames:{}", this.factoryNamesToQNames);
     }
index 28bd613648d31bfcb6072737b065ceaa07bf7390..15c69bf25fe4db456ae9a7890ad389f8f953251a 100644 (file)
@@ -28,15 +28,18 @@ public class TransactionIdentifier implements Identifier {
 
     @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;
+        }
 
         TransactionIdentifier that = (TransactionIdentifier) o;
 
-        if (name != null ? !name.equals(that.name) : that.name != null)
+        if (name != null ? !name.equals(that.name) : that.name != null) {
             return false;
+        }
 
         return true;
     }
index a25062074b8384837a46924d77dc0badc4a03eac..f86d6b1d818715481f601a4e366240aae2e5d4a5 100644 (file)
@@ -48,18 +48,21 @@ public class TransactionStatus {
     }
 
     public synchronized void checkNotCommitStarted() {
-        if (secondPhaseCommitStarted == true)
+        if (secondPhaseCommitStarted == true) {
             throw new IllegalStateException("Commit was triggered");
+        }
     }
 
     public synchronized void checkCommitStarted() {
-        if (secondPhaseCommitStarted == false)
+        if (secondPhaseCommitStarted == false) {
             throw new IllegalStateException("Commit was not triggered");
+        }
     }
 
     public synchronized void checkNotAborted() {
-        if (aborted == true)
+        if (aborted == true) {
             throw new IllegalStateException("Configuration was aborted");
+        }
     }
 
     public synchronized void checkNotCommitted() {
index ec9678fd2d7df3545f15bc5a8fa0e7b8129b5760..c229450c30138584e615e552843c1b0f10581dca 100644 (file)
@@ -39,7 +39,7 @@ import static java.lang.String.format;
  * during validation. Tracks dependencies for ordering purposes.
  */
 final class DependencyResolverImpl implements DependencyResolver,
-       Comparable<DependencyResolverImpl> {
+        Comparable<DependencyResolverImpl> {
     private static final Logger logger = LoggerFactory.getLogger(DependencyResolverImpl.class);
 
     private final ModulesHolder modulesHolder;
@@ -74,15 +74,15 @@ final class DependencyResolverImpl implements DependencyResolver,
             throw new NullPointerException(
                     "Parameter 'expectedServiceInterface' is null");
         }
-        if (jmxAttribute == null)
+        if (jmxAttribute == null) {
             throw new NullPointerException("Parameter 'jmxAttribute' is null");
+        }
 
         JmxAttributeValidationException.checkNotNull(dependentReadOnlyON,
                 "is null, expected dependency implementing "
                         + expectedServiceInterface, jmxAttribute);
 
 
-
         // check that objectName belongs to this transaction - this should be
         // stripped
         // in DynamicWritableWrapper
@@ -118,7 +118,7 @@ final class DependencyResolverImpl implements DependencyResolver,
         }
     }
 
-    // transalate from serviceref to module ON
+    // translate from serviceref to module ON
     private ObjectName translateServiceRefIfPossible(ObjectName dependentReadOnlyON) {
         if (ObjectNameUtil.isServiceReference(dependentReadOnlyON)) {
             String serviceQName = ObjectNameUtil.getServiceQName(dependentReadOnlyON);
@@ -135,7 +135,7 @@ final class DependencyResolverImpl implements DependencyResolver,
     //TODO: check for cycles
     @Override
     public <T> T resolveInstance(Class<T> expectedType, ObjectName dependentReadOnlyON,
-            JmxAttribute jmxAttribute) {
+                                 JmxAttribute jmxAttribute) {
         if (expectedType == null || dependentReadOnlyON == null || jmxAttribute == null) {
             throw new IllegalArgumentException(format(
                     "Null parameters not allowed, got %s %s %s", expectedType,
@@ -161,8 +161,7 @@ final class DependencyResolverImpl implements DependencyResolver,
             throw new JmxAttributeValidationException(message, jmxAttribute);
         }
         try {
-            T result = expectedType.cast(instance);
-            return result;
+            return expectedType.cast(instance);
         } catch (ClassCastException e) {
             String message = format(
                     "Instance cannot be cast to expected type. Instance class is %s , "
@@ -178,7 +177,7 @@ final class DependencyResolverImpl implements DependencyResolver,
         IdentityCodec<?> identityCodec = codecRegistry.getIdentityCodec();
         Class<? extends BaseIdentity> deserialized = identityCodec.deserialize(qName);
         if (deserialized == null) {
-            throw new RuntimeException("Unable to retrieve identity class for " + qName + ", null response from "
+            throw new IllegalStateException("Unable to retrieve identity class for " + qName + ", null response from "
                     + codecRegistry);
         }
         if (expectedBaseClass.isAssignableFrom(deserialized)) {
@@ -194,7 +193,7 @@ final class DependencyResolverImpl implements DependencyResolver,
     public <T extends BaseIdentity> void validateIdentity(IdentityAttributeRef identityRef, Class<T> expectedBaseClass, JmxAttribute jmxAttribute) {
         try {
             resolveIdentity(identityRef, expectedBaseClass);
-        } catch(Exception e) {
+        } catch (Exception e) {
             throw JmxAttributeValidationException.wrap(e, jmxAttribute);
         }
     }
@@ -215,7 +214,7 @@ final class DependencyResolverImpl implements DependencyResolver,
         return maxDependencyDepth;
     }
 
-    public void countMaxDependencyDepth(DependencyResolverManager manager) {
+    void countMaxDependencyDepth(DependencyResolverManager manager) {
         transactionStatus.checkCommitted();
         if (maxDependencyDepth == null) {
             maxDependencyDepth = getMaxDepth(this, manager,
@@ -224,8 +223,8 @@ final class DependencyResolverImpl implements DependencyResolver,
     }
 
     private static int getMaxDepth(DependencyResolverImpl impl,
-            DependencyResolverManager manager,
-            LinkedHashSet<ModuleIdentifier> chainForDetectingCycles) {
+                                   DependencyResolverManager manager,
+                                   LinkedHashSet<ModuleIdentifier> chainForDetectingCycles) {
         int maxDepth = 0;
         LinkedHashSet<ModuleIdentifier> chainForDetectingCycles2 = new LinkedHashSet<>(
                 chainForDetectingCycles);
@@ -258,4 +257,5 @@ final class DependencyResolverImpl implements DependencyResolver,
     public ModuleIdentifier getIdentifier() {
         return name;
     }
+
 }
index c115934d370dc29b4c80dbe18dc33fb75ed6c5c9..b99bf8330e5be412a6965ff78ccad4bb4b520c14 100644 (file)
@@ -7,45 +7,57 @@
  */
 package org.opendaylight.controller.config.manager.impl.dependencyresolver;
 
+import com.google.common.reflect.AbstractInvocationHandler;
+import com.google.common.reflect.Reflection;
 import org.opendaylight.controller.config.api.DependencyResolver;
 import org.opendaylight.controller.config.api.DependencyResolverFactory;
 import org.opendaylight.controller.config.api.JmxAttribute;
 import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.api.RuntimeBeanRegistratorAwareModule;
 import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
 import org.opendaylight.controller.config.manager.impl.CommitInfo;
-import org.opendaylight.controller.config.manager.impl.ModuleInternalTransactionalInfo;
+import org.opendaylight.controller.config.manager.impl.DeadlockMonitor;
+import org.opendaylight.controller.config.manager.impl.ModuleInternalInfo;
+import org.opendaylight.controller.config.manager.impl.TransactionIdentifier;
 import org.opendaylight.controller.config.manager.impl.TransactionStatus;
+import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator.TransactionModuleJMXRegistration;
 import org.opendaylight.controller.config.spi.Module;
 import org.opendaylight.controller.config.spi.ModuleFactory;
 import org.opendaylight.yangtools.yang.data.impl.codec.CodecRegistry;
 
 import javax.annotation.concurrent.GuardedBy;
 import javax.management.InstanceAlreadyExistsException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import static com.google.common.base.Preconditions.checkState;
+
 /**
  * Holds information about modules being created and destroyed within this
  * transaction. Observes usage of DependencyResolver within modules to figure
  * out dependency tree.
  */
-public class DependencyResolverManager implements TransactionHolder, DependencyResolverFactory {
+public class DependencyResolverManager implements DependencyResolverFactory, AutoCloseable {
     @GuardedBy("this")
     private final Map<ModuleIdentifier, DependencyResolverImpl> moduleIdentifiersToDependencyResolverMap = new HashMap<>();
     private final ModulesHolder modulesHolder;
     private final TransactionStatus transactionStatus;
     private final ServiceReferenceReadableRegistry readableRegistry;
     private final CodecRegistry codecRegistry;
+    private final DeadlockMonitor deadlockMonitor;
 
-    public DependencyResolverManager(String transactionName,
+    public DependencyResolverManager(TransactionIdentifier transactionIdentifier,
                                      TransactionStatus transactionStatus, ServiceReferenceReadableRegistry readableRegistry, CodecRegistry codecRegistry) {
-        this.modulesHolder = new ModulesHolder(transactionName);
+        this.modulesHolder = new ModulesHolder(transactionIdentifier);
         this.transactionStatus = transactionStatus;
         this.readableRegistry = readableRegistry;
         this.codecRegistry = codecRegistry;
+        this.deadlockMonitor = new DeadlockMonitor(transactionIdentifier);
     }
 
     @Override
@@ -88,7 +100,6 @@ public class DependencyResolverManager implements TransactionHolder, DependencyR
         return result;
     }
 
-    @Override
     public ModuleInternalTransactionalInfo destroyModule(
             ModuleIdentifier moduleIdentifier) {
         transactionStatus.checkNotCommitted();
@@ -99,45 +110,85 @@ public class DependencyResolverManager implements TransactionHolder, DependencyR
     }
 
     // protect write access
-    @Override
+
     public void put(
-            ModuleInternalTransactionalInfo moduleInternalTransactionalInfo) {
+            final ModuleIdentifier moduleIdentifier,
+            final Module module,
+            ModuleFactory moduleFactory,
+            ModuleInternalInfo maybeOldInternalInfo,
+            TransactionModuleJMXRegistration transactionModuleJMXRegistration,
+            boolean isDefaultBean) {
         transactionStatus.checkNotCommitted();
+
+        Class<? extends Module> moduleClass = Module.class;
+        if (module instanceof RuntimeBeanRegistratorAwareModule) {
+            moduleClass = RuntimeBeanRegistratorAwareModule.class;
+        }
+        Module proxiedModule = Reflection.newProxy(moduleClass, new AbstractInvocationHandler() {
+            // optimization: subsequent calls to getInstance MUST return the same value during transaction,
+            // so it is safe to cache the response
+            private Object cachedInstance;
+
+            @Override
+            protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
+                boolean isGetInstance = method.getName().equals("getInstance");
+                if (isGetInstance) {
+                    if (cachedInstance != null) {
+                        return cachedInstance;
+                    }
+
+                    checkState(deadlockMonitor.isAlive(), "Deadlock monitor is not alive");
+                    deadlockMonitor.setCurrentlyInstantiatedModule(moduleIdentifier);
+                }
+                try {
+                    Object response = method.invoke(module, args);
+                    if (isGetInstance) {
+                        cachedInstance = response;
+                    }
+                    return response;
+                } catch(InvocationTargetException e) {
+                    throw e.getCause();
+                } finally {
+                    if (isGetInstance) {
+                        deadlockMonitor.setCurrentlyInstantiatedModule(null);
+                    }
+                }
+            }
+        });
+
+
+        ModuleInternalTransactionalInfo moduleInternalTransactionalInfo = new ModuleInternalTransactionalInfo(
+                moduleIdentifier, proxiedModule, moduleFactory,
+                maybeOldInternalInfo, transactionModuleJMXRegistration, isDefaultBean, module);
         modulesHolder.put(moduleInternalTransactionalInfo);
     }
 
     // wrapped methods:
 
-    @Override
     public CommitInfo toCommitInfo() {
         return modulesHolder.toCommitInfo();
     }
 
-    @Override
     public Module findModule(ModuleIdentifier moduleIdentifier,
-            JmxAttribute jmxAttributeForReporting) {
+                             JmxAttribute jmxAttributeForReporting) {
         return modulesHolder.findModule(moduleIdentifier,
                 jmxAttributeForReporting);
     }
 
-    @Override
     public ModuleInternalTransactionalInfo findModuleInternalTransactionalInfo(ModuleIdentifier moduleIdentifier) {
         return modulesHolder.findModuleInternalTransactionalInfo(moduleIdentifier);
     }
 
-    @Override
     public ModuleFactory findModuleFactory(ModuleIdentifier moduleIdentifier,
-            JmxAttribute jmxAttributeForReporting) {
+                                           JmxAttribute jmxAttributeForReporting) {
         return modulesHolder.findModuleFactory(moduleIdentifier,
                 jmxAttributeForReporting);
     }
 
-    @Override
     public Map<ModuleIdentifier, Module> getAllModules() {
         return modulesHolder.getAllModules();
     }
 
-    @Override
     public void assertNotExists(ModuleIdentifier moduleIdentifier)
             throws InstanceAlreadyExistsException {
         modulesHolder.assertNotExists(moduleIdentifier);
@@ -145,11 +196,16 @@ public class DependencyResolverManager implements TransactionHolder, DependencyR
 
     public List<ModuleIdentifier> findAllByFactory(ModuleFactory factory) {
         List<ModuleIdentifier> result = new ArrayList<>();
-        for( ModuleInternalTransactionalInfo  info : modulesHolder.getAllInfos()) {
+        for (ModuleInternalTransactionalInfo info : modulesHolder.getAllInfos()) {
             if (factory.equals(info.getModuleFactory())) {
                 result.add(info.getIdentifier());
             }
         }
         return result;
     }
+
+    public void close() {
+        deadlockMonitor.close();
+    }
+
 }
@@ -5,7 +5,7 @@
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
-package org.opendaylight.controller.config.manager.impl;
+package org.opendaylight.controller.config.manager.impl.dependencyresolver;
 
 import org.opendaylight.controller.config.api.ModuleIdentifier;
 import org.opendaylight.controller.config.manager.impl.jmx.ModuleJMXRegistrator;
@@ -31,7 +31,7 @@ public class DestroyedModule implements AutoCloseable,
     private final OsgiRegistration osgiRegistration;
     private final int orderingIdx;
 
-    DestroyedModule(ModuleIdentifier identifier, AutoCloseable instance,
+    public DestroyedModule(ModuleIdentifier identifier, AutoCloseable instance,
             ModuleJMXRegistrator oldJMXRegistrator,
             OsgiRegistration osgiRegistration, int orderingIdx) {
         this.identifier = identifier;
@@ -5,38 +5,39 @@
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
-package org.opendaylight.controller.config.manager.impl;
-
-import javax.annotation.Nullable;
+package org.opendaylight.controller.config.manager.impl.dependencyresolver;
 
 import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.manager.impl.ModuleInternalInfo;
 import org.opendaylight.controller.config.manager.impl.dynamicmbean.DynamicReadableWrapper;
-import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator
-        .TransactionModuleJMXRegistration;
+import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator.TransactionModuleJMXRegistration;
 import org.opendaylight.controller.config.spi.Module;
 import org.opendaylight.controller.config.spi.ModuleFactory;
 import org.opendaylight.yangtools.concepts.Identifiable;
 
+import javax.annotation.Nullable;
+
 public class ModuleInternalTransactionalInfo implements Identifiable<ModuleIdentifier> {
     private final ModuleIdentifier name;
-    private final Module module;
+    private final Module proxiedModule, realModule;
     private final ModuleFactory moduleFactory;
     @Nullable
     private final ModuleInternalInfo maybeOldInternalInfo;
     private final TransactionModuleJMXRegistration transactionModuleJMXRegistration;
     private final boolean isDefaultBean;
 
-    ModuleInternalTransactionalInfo(ModuleIdentifier name, Module module,
-            ModuleFactory moduleFactory,
-            ModuleInternalInfo maybeOldInternalInfo,
-            TransactionModuleJMXRegistration transactionModuleJMXRegistration,
-            boolean isDefaultBean) {
+    public ModuleInternalTransactionalInfo(ModuleIdentifier name, Module proxiedModule,
+                                           ModuleFactory moduleFactory,
+                                           ModuleInternalInfo maybeOldInternalInfo,
+                                           TransactionModuleJMXRegistration transactionModuleJMXRegistration,
+                                           boolean isDefaultBean, Module realModule) {
         this.name = name;
-        this.module = module;
+        this.proxiedModule = proxiedModule;
         this.moduleFactory = moduleFactory;
         this.maybeOldInternalInfo = maybeOldInternalInfo;
         this.transactionModuleJMXRegistration = transactionModuleJMXRegistration;
         this.isDefaultBean = isDefaultBean;
+        this.realModule = realModule;
     }
 
 
@@ -57,8 +58,8 @@ public class ModuleInternalTransactionalInfo implements Identifiable<ModuleIdent
     }
 
 
-    public Module getModule() {
-        return module;
+    public Module getProxiedModule() {
+        return proxiedModule;
     }
 
     public ModuleFactory getModuleFactory() {
@@ -67,8 +68,9 @@ public class ModuleInternalTransactionalInfo implements Identifiable<ModuleIdent
 
     @Nullable
     public ModuleInternalInfo getOldInternalInfo() {
-        if (maybeOldInternalInfo == null)
+        if (maybeOldInternalInfo == null) {
             throw new NullPointerException();
+        }
         return maybeOldInternalInfo;
     }
 
@@ -84,4 +86,8 @@ public class ModuleInternalTransactionalInfo implements Identifiable<ModuleIdent
     public boolean isDefaultBean() {
         return isDefaultBean;
     }
+
+    public Module getRealModule() {
+        return realModule;
+    }
 }
index 7c7d9f95a4e71899ff5feec39bdb5433ebc6baa6..81cc34ac970f8540943b12cf1d45549329b95e46 100644 (file)
@@ -11,8 +11,7 @@ import org.opendaylight.controller.config.api.JmxAttribute;
 import org.opendaylight.controller.config.api.JmxAttributeValidationException;
 import org.opendaylight.controller.config.api.ModuleIdentifier;
 import org.opendaylight.controller.config.manager.impl.CommitInfo;
-import org.opendaylight.controller.config.manager.impl.DestroyedModule;
-import org.opendaylight.controller.config.manager.impl.ModuleInternalTransactionalInfo;
+import org.opendaylight.controller.config.manager.impl.TransactionIdentifier;
 import org.opendaylight.controller.config.spi.Module;
 import org.opendaylight.controller.config.spi.ModuleFactory;
 
@@ -30,19 +29,19 @@ import java.util.Set;
 /**
  * Represents modules to be committed.
  */
-class ModulesHolder implements TransactionHolder {
-    private final String transactionName;
+class ModulesHolder {
+    private final TransactionIdentifier transactionIdentifier;
     @GuardedBy("this")
     private final Map<ModuleIdentifier, ModuleInternalTransactionalInfo> commitMap = new HashMap<>();
 
     @GuardedBy("this")
     private final Set<ModuleInternalTransactionalInfo> unorderedDestroyedFromPreviousTransactions = new HashSet<>();
 
-    ModulesHolder(String transactionName) {
-        this.transactionName = transactionName;
+    ModulesHolder(TransactionIdentifier transactionIdentifier) {
+        this.transactionIdentifier = transactionIdentifier;
     }
 
-    @Override
+
     public CommitInfo toCommitInfo() {
         List<DestroyedModule> orderedDestroyedFromPreviousTransactions = new ArrayList<>(
                 unorderedDestroyedFromPreviousTransactions.size());
@@ -62,43 +61,38 @@ class ModulesHolder implements TransactionHolder {
                 .get(moduleIdentifier);
         JmxAttributeValidationException.checkNotNull(
                 moduleInternalTransactionalInfo, "Module " + moduleIdentifier
-                        + "" + " not found in transaction " + transactionName,
+                        + "" + " not found in transaction " + transactionIdentifier,
                 jmxAttributeForReporting);
         return moduleInternalTransactionalInfo;
     }
 
-    @Override
     public Module findModule(ModuleIdentifier moduleIdentifier,
             JmxAttribute jmxAttributeForReporting) {
         return findModuleInternalTransactionalInfo(moduleIdentifier,
-                jmxAttributeForReporting).getModule();
+                jmxAttributeForReporting).getProxiedModule();
     }
 
-    @Override
     public ModuleFactory findModuleFactory(ModuleIdentifier moduleIdentifier,
             JmxAttribute jmxAttributeForReporting) {
         return findModuleInternalTransactionalInfo(moduleIdentifier,
                 jmxAttributeForReporting).getModuleFactory();
     }
 
-    @Override
     public Map<ModuleIdentifier, Module> getAllModules() {
         Map<ModuleIdentifier, Module> result = new HashMap<>();
         for (ModuleInternalTransactionalInfo entry : commitMap.values()) {
             ModuleIdentifier name = entry.getIdentifier();
-            result.put(name, entry.getModule());
+            result.put(name, entry.getProxiedModule());
         }
         return result;
     }
 
-    @Override
     public void put(
             ModuleInternalTransactionalInfo moduleInternalTransactionalInfo) {
         commitMap.put(moduleInternalTransactionalInfo.getIdentifier(),
                 moduleInternalTransactionalInfo);
     }
 
-    @Override
     public ModuleInternalTransactionalInfo destroyModule(
             ModuleIdentifier moduleIdentifier) {
         ModuleInternalTransactionalInfo found = commitMap.remove(moduleIdentifier);
@@ -111,7 +105,6 @@ class ModulesHolder implements TransactionHolder {
         return found;
     }
 
-    @Override
     public void assertNotExists(ModuleIdentifier moduleIdentifier)
             throws InstanceAlreadyExistsException {
         if (commitMap.containsKey(moduleIdentifier)) {
@@ -124,7 +117,6 @@ class ModulesHolder implements TransactionHolder {
         return commitMap.values();
     }
 
-    @Override
     public ModuleInternalTransactionalInfo findModuleInternalTransactionalInfo(ModuleIdentifier moduleIdentifier) {
         ModuleInternalTransactionalInfo found = commitMap.get(moduleIdentifier);
         if (found == null) {
diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/TransactionHolder.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/TransactionHolder.java
deleted file mode 100644 (file)
index bccd453..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.config.manager.impl.dependencyresolver;
-
-import org.opendaylight.controller.config.api.JmxAttribute;
-import org.opendaylight.controller.config.api.ModuleIdentifier;
-import org.opendaylight.controller.config.manager.impl.CommitInfo;
-import org.opendaylight.controller.config.manager.impl.ModuleInternalTransactionalInfo;
-import org.opendaylight.controller.config.spi.Module;
-import org.opendaylight.controller.config.spi.ModuleFactory;
-
-import javax.management.InstanceAlreadyExistsException;
-import java.util.Map;
-
-interface TransactionHolder {
-    CommitInfo toCommitInfo();
-
-    Module findModule(ModuleIdentifier moduleIdentifier,
-            JmxAttribute jmxAttributeForReporting);
-
-    ModuleFactory findModuleFactory(ModuleIdentifier moduleIdentifier,
-            JmxAttribute jmxAttributeForReporting);
-
-    Map<ModuleIdentifier, Module> getAllModules();
-
-    void put(ModuleInternalTransactionalInfo moduleInternalTransactionalInfo);
-
-    ModuleInternalTransactionalInfo destroyModule(
-            ModuleIdentifier moduleIdentifier);
-
-    void assertNotExists(ModuleIdentifier moduleIdentifier)
-            throws InstanceAlreadyExistsException;
-
-    ModuleInternalTransactionalInfo findModuleInternalTransactionalInfo(ModuleIdentifier moduleIdentifier);
-
-}
index 6f0d1b2682a00e17b8935cca72c86599cd2b2b63..7e48af1caae9adc31cb0c76b64a86d0fb7bca428 100644 (file)
@@ -55,7 +55,6 @@ import static java.lang.String.format;
  * requests (getAttribute, setAttribute, invoke) into the actual instance, but
  * provides additional functionality - namely it disallows setting attribute on
  * a read only wrapper.
- *
  */
 abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper {
     private static final Logger logger = LoggerFactory
@@ -71,9 +70,9 @@ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper {
     protected final MBeanServer internalServer;
 
     public AbstractDynamicWrapper(Module module, boolean writable,
-            ModuleIdentifier moduleIdentifier,
-            ObjectName thisWrapperObjectName, MBeanOperationInfo[] dOperations,
-            MBeanServer internalServer, MBeanServer configMBeanServer) {
+                                  ModuleIdentifier moduleIdentifier,
+                                  ObjectName thisWrapperObjectName, MBeanOperationInfo[] dOperations,
+                                  MBeanServer internalServer, MBeanServer configMBeanServer) {
 
         this.writable = writable;
         this.module = module;
@@ -98,10 +97,10 @@ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper {
      * case unregister the module and remove listener.
      */
     private final NotificationListener registerActualModule(Module module,
-            final ObjectName thisWrapperObjectName,
-            final ObjectName objectNameInternal,
-            final MBeanServer internalServer,
-            final MBeanServer configMBeanServer) {
+                                                            final ObjectName thisWrapperObjectName,
+                                                            final ObjectName objectNameInternal,
+                                                            final MBeanServer internalServer,
+                                                            final MBeanServer configMBeanServer) {
 
         try {
             internalServer.registerMBean(module, objectNameInternal);
@@ -116,7 +115,7 @@ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper {
             public void handleNotification(Notification n, Object handback) {
                 if (n instanceof MBeanServerNotification
                         && n.getType()
-                                .equals(MBeanServerNotification.UNREGISTRATION_NOTIFICATION)) {
+                        .equals(MBeanServerNotification.UNREGISTRATION_NOTIFICATION)) {
                     if (((MBeanServerNotification) n).getMBeanName().equals(
                             thisWrapperObjectName)) {
                         try {
@@ -142,8 +141,8 @@ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper {
     }
 
     private static MBeanInfo generateMBeanInfo(String className, Module module,
-            Map<String, AttributeHolder> attributeHolderMap,
-            MBeanOperationInfo[] dOperations, Set<Class<?>> jmxInterfaces) {
+                                               Map<String, AttributeHolder> attributeHolderMap,
+                                               MBeanOperationInfo[] dOperations, Set<Class<?>> jmxInterfaces) {
 
         String dDescription = findDescription(module.getClass(), jmxInterfaces);
         MBeanConstructorInfo[] dConstructors = new MBeanConstructorInfo[0];
@@ -170,9 +169,9 @@ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper {
     // inspect all exported interfaces ending with MXBean, extract getters &
     // setters into attribute holder
     private static Map<String, AttributeHolder> buildMBeanInfo(Module module,
-            boolean writable, ModuleIdentifier moduleIdentifier,
-            Set<Class<?>> jmxInterfaces, MBeanServer internalServer,
-            ObjectName internalObjectName) {
+                                                               boolean writable, ModuleIdentifier moduleIdentifier,
+                                                               Set<Class<?>> jmxInterfaces, MBeanServer internalServer,
+                                                               ObjectName internalObjectName) {
 
         // internal variables for describing MBean elements
         Set<Method> methods = new HashSet<>();
@@ -217,7 +216,7 @@ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper {
                 }
                 AttributeHolder attributeHolder = new AttributeHolder(
                         attribName, module, attributeMap.get(attribName)
-                                .getType(), writable, ifc, description);
+                        .getType(), writable, ifc, description);
                 attributeHolderMap.put(attribName, attributeHolder);
             }
         }
@@ -257,7 +256,7 @@ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper {
         }
 
 
-        if(isDependencyListAttr(attributeName, obj)) {
+        if (isDependencyListAttr(attributeName, obj)) {
             obj = fixDependencyListAttribute(obj);
         }
 
@@ -265,14 +264,16 @@ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper {
     }
 
     private Object fixDependencyListAttribute(Object attribute) {
-        if(attribute.getClass().isArray() == false)
+        if (attribute.getClass().isArray() == false) {
             throw new IllegalArgumentException("Unexpected attribute type, should be an array, but was " + attribute.getClass());
+        }
 
         for (int i = 0; i < Array.getLength(attribute); i++) {
 
             Object on = Array.get(attribute, i);
-            if(on instanceof ObjectName == false)
+            if (on instanceof ObjectName == false) {
                 throw new IllegalArgumentException("Unexpected attribute type, should be an ObjectName, but was " + on.getClass());
+            }
             on = fixObjectName((ObjectName) on);
 
             Array.set(attribute, i, on);
@@ -282,8 +283,9 @@ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper {
     }
 
     private boolean isDependencyListAttr(String attributeName, Object attribute) {
-        if (attributeHolderMap.containsKey(attributeName) == false)
+        if (attributeHolderMap.containsKey(attributeName) == false) {
             return false;
+        }
 
         AttributeHolder attributeHolder = attributeHolderMap.get(attributeName);
 
@@ -294,15 +296,17 @@ abstract class AbstractDynamicWrapper implements DynamicMBeanModuleWrapper {
     }
 
     protected ObjectName fixObjectName(ObjectName on) {
-        if (!ObjectNameUtil.ON_DOMAIN.equals(on.getDomain()))
+        if (!ObjectNameUtil.ON_DOMAIN.equals(on.getDomain())) {
             throw new IllegalArgumentException("Wrong domain, expected "
                     + ObjectNameUtil.ON_DOMAIN + " setter on " + on);
+        }
         // if on contains transaction name, remove it
         String transactionName = ObjectNameUtil.getTransactionName(on);
-        if (transactionName != null)
+        if (transactionName != null) {
             return ObjectNameUtil.withoutTransactionName(on);
-        else
+        } else {
             return on;
+        }
     }
 
     @Override
index 64664f79802bc62b10f7e895df7efe36418effe0..f3e1b4e705c3b943230d13ee52eca44bd798b930 100644 (file)
@@ -7,15 +7,15 @@
  */
 package org.opendaylight.controller.config.manager.impl.dynamicmbean;
 
+import org.opendaylight.controller.config.api.annotations.Description;
+
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 
-import org.opendaylight.controller.config.api.annotations.Description;
-
-class AnnotationsHelper {
+public class AnnotationsHelper {
 
     /**
      * Look for annotation specified by annotationType on method. First observe
index 9dd6a2269e259cf4ca5ee4e6b1331d85ef015d81..044f7a9ada06af871fad5bc1cad531e550bab8c8 100644 (file)
@@ -40,9 +40,9 @@ class AttributeHolder {
     }
 
     public AttributeHolder(String name, Object object, String returnType,
-            boolean writable,
-            @Nullable RequireInterface requireInterfaceAnnotation,
-            String description) {
+                           boolean writable,
+                           @Nullable RequireInterface requireInterfaceAnnotation,
+                           String description) {
         if (name == null) {
             throw new NullPointerException();
         }
@@ -65,7 +65,7 @@ class AttributeHolder {
 
     /**
      * @return annotation if setter sets ObjectName or ObjectName[], and is
-     *         annotated. Return null otherwise.
+     * annotated. Return null otherwise.
      */
     RequireInterface getRequireInterfaceOrNull() {
         return requireInterfaceAnnotation;
@@ -98,7 +98,7 @@ class AttributeHolder {
      * @param setter
      * @param jmxInterfaces
      * @return empty string if no annotation is found, or list of descriptions
-     *         separated by newline
+     * separated by newline
      */
     static String findDescription(Method setter, Set<Class<?>> jmxInterfaces) {
         List<Description> descriptions = AnnotationsHelper
@@ -112,21 +112,21 @@ class AttributeHolder {
      *
      * @param setter
      * @param inspectedInterfaces
-     * @throws IllegalStateException
-     *             if more than one value is specified by found annotations
-     * @throws IllegalArgumentException
-     *             if set of exported interfaces contains non interface type
      * @return null if no annotation is found, otherwise return the annotation
+     * @throws IllegalStateException    if more than one value is specified by found annotations
+     * @throws IllegalArgumentException if set of exported interfaces contains non interface type
      */
     static RequireInterface findRequireInterfaceAnnotation(final Method setter,
-            Set<Class<?>> inspectedInterfaces) {
+                                                           Set<Class<?>> inspectedInterfaces) {
 
         // only allow setX(ObjectName y) or setX(ObjectName[] y) or setX(List<ObjectName> y) to continue
 
-        if (setter.getParameterTypes().length > 1)
+        if (setter.getParameterTypes().length > 1) {
             return null;
-        if(PERMITTED_PARAMETER_TYPES_FOR_DEPENDENCY_SETTER.contains(setter.getParameterTypes()[0]) == false)
+        }
+        if (PERMITTED_PARAMETER_TYPES_FOR_DEPENDENCY_SETTER.contains(setter.getParameterTypes()[0]) == false) {
             return null;
+        }
 
         List<RequireInterface> foundRequireInterfaces = AnnotationsHelper
                 .findMethodAnnotationInSuperClassesAndIfcs(setter, RequireInterface.class, inspectedInterfaces);
index 2ab04e53e304fa8909543ded413b408941566fcc..335acc81fe67859386b3369269c15f3101d7e2f4 100644 (file)
@@ -164,8 +164,9 @@ public class DynamicWritableWrapper extends AbstractDynamicWrapper {
             try {
                 validate();
             } catch (Exception e) {
-                throw ValidationException.createForSingleException(
-                        moduleIdentifier, e);
+
+                throw new MBeanException(ValidationException.createForSingleException(
+                        moduleIdentifier, e));
             }
             return Void.TYPE;
         }
index 16f7cf024a40958118467641736eae6ebecfcd98..adc8168af5d85b0aee22e717cb59cda7b8939b8f 100644 (file)
@@ -10,25 +10,21 @@ package org.opendaylight.controller.config.manager.impl.factoriesresolver;
 
 import org.opendaylight.controller.config.spi.ModuleFactory;
 import org.osgi.framework.BundleContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
-import java.util.Map.Entry;
-import java.util.Set;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
-import java.util.Collections;
+import java.util.Map.Entry;
+import java.util.Set;
 import java.util.TreeSet;
-import java.util.Collection;
-import java.util.ArrayList;
 
 /**
  * Hold sorted ConfigMBeanFactories by their module names. Check that module
  * names are globally unique.
  */
 public class HierarchicalConfigMBeanFactoriesHolder {
-    private static final Logger logger = LoggerFactory
-            .getLogger(HierarchicalConfigMBeanFactoriesHolder.class);
 
     private final Map<String, Map.Entry<ModuleFactory, BundleContext>> moduleNamesToConfigBeanFactories;
     private final Set<String> moduleNames;
index 5d771560a53b5dd25a3ec2140b5c2bf74f1791c0..98f0908dc710cf40fbb93b88004d411d03f594fd 100644 (file)
@@ -7,22 +7,24 @@
  */
 package org.opendaylight.controller.config.manager.impl.jmx;
 
-import java.io.Closeable;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import javax.annotation.concurrent.GuardedBy;
 import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
 import javax.management.JMX;
+import javax.management.MBeanRegistrationException;
 import javax.management.MBeanServer;
+import javax.management.NotCompliantMBeanException;
 import javax.management.ObjectName;
 import javax.management.QueryExp;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import java.io.Closeable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 
 public class InternalJMXRegistrator implements Closeable {
     private static final Logger logger = LoggerFactory
@@ -38,7 +40,7 @@ public class InternalJMXRegistrator implements Closeable {
         private final ObjectName on;
 
         InternalJMXRegistration(InternalJMXRegistrator internalJMXRegistrator,
-                ObjectName on) {
+                                ObjectName on) {
             this.internalJMXRegistrator = internalJMXRegistrator;
             this.on = on;
         }
@@ -54,13 +56,11 @@ public class InternalJMXRegistrator implements Closeable {
     private final List<InternalJMXRegistrator> children = new ArrayList<>();
 
     public synchronized InternalJMXRegistration registerMBean(Object object,
-            ObjectName on) throws InstanceAlreadyExistsException {
+                                                              ObjectName on) throws InstanceAlreadyExistsException {
         try {
             configMBeanServer.registerMBean(object, on);
-        } catch (InstanceAlreadyExistsException e) {
-            throw e;
-        } catch (Exception e) {
-            throw new RuntimeException(e);
+        } catch (MBeanRegistrationException | NotCompliantMBeanException e) {
+            throw new IllegalStateException(e);
         }
         registeredObjectNames.add(on);
         return new InternalJMXRegistration(this, on);
@@ -69,14 +69,13 @@ public class InternalJMXRegistrator implements Closeable {
     private synchronized void unregisterMBean(ObjectName on) {
         // first check that on was registered using this instance
         boolean removed = registeredObjectNames.remove(on);
-        if (!removed)
-            throw new IllegalStateException(
-                    "Cannot unregister - ObjectName not found in 'registeredObjectNames': "
-                            + on);
+        if (!removed) {
+            throw new IllegalStateException("Cannot unregister - ObjectName not found in 'registeredObjectNames': " + on);
+        }
         try {
             configMBeanServer.unregisterMBean(on);
-        } catch (Exception e) {
-            throw new RuntimeException(e);
+        } catch (InstanceNotFoundException | MBeanRegistrationException e) {
+            throw new IllegalStateException(e);
         }
     }
 
@@ -112,7 +111,7 @@ public class InternalJMXRegistrator implements Closeable {
     }
 
     public <T> T newMBeanProxy(ObjectName objectName, Class<T> interfaceClass,
-            boolean notificationBroadcaster) {
+                               boolean notificationBroadcaster) {
         return JMX.newMBeanProxy(configMBeanServer, objectName, interfaceClass,
                 notificationBroadcaster);
     }
@@ -123,7 +122,7 @@ public class InternalJMXRegistrator implements Closeable {
     }
 
     public <T> T newMXBeanProxy(ObjectName objectName, Class<T> interfaceClass,
-            boolean notificationBroadcaster) {
+                                boolean notificationBroadcaster) {
         return JMX.newMXBeanProxy(configMBeanServer, objectName,
                 interfaceClass, notificationBroadcaster);
     }
index 849f75234f05ccec20361066de8140ef37a5659e..cd74ddf7565a32fd74e650cde1d50e720966d506 100644 (file)
@@ -25,13 +25,21 @@ public class ServiceReference {
 
     @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;
+        }
 
         ServiceReference that = (ServiceReference) o;
 
-        if (!refName.equals(that.refName)) return false;
-        if (!serviceInterfaceName.equals(that.serviceInterfaceName)) return false;
+        if (!refName.equals(that.refName)) {
+            return false;
+        }
+        if (!serviceInterfaceName.equals(that.serviceInterfaceName)) {
+            return false;
+        }
 
         return true;
     }
index b371c3f1709c3160bc2c2a372f0d7647dec24253..6fd2a2fc65201ea0d48c974875e2fe9477300ac0 100644 (file)
@@ -7,15 +7,14 @@
  */
 package org.opendaylight.controller.config.manager.impl.jmx;
 
-import java.io.Closeable;
-import java.util.Set;
+import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.config.manager.impl.jmx.InternalJMXRegistrator.InternalJMXRegistration;
 
 import javax.management.InstanceAlreadyExistsException;
 import javax.management.ObjectName;
 import javax.management.QueryExp;
-
-import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.config.manager.impl.jmx.InternalJMXRegistrator.InternalJMXRegistration;
+import java.io.Closeable;
+import java.util.Set;
 
 /**
  * Contains constraints on passed {@link ObjectName} parameters. Only allow (un)
@@ -26,7 +25,7 @@ public class TransactionJMXRegistrator implements Closeable {
     private final String transactionName;
 
     TransactionJMXRegistrator(InternalJMXRegistrator internalJMXRegistrator,
-            String transactionName) {
+                              String transactionName) {
         this.childJMXRegistrator = internalJMXRegistrator.createChild();
         this.transactionName = transactionName;
     }
@@ -46,10 +45,11 @@ public class TransactionJMXRegistrator implements Closeable {
 
     public TransactionJMXRegistration registerMBean(Object object, ObjectName on)
             throws InstanceAlreadyExistsException {
-        if (!transactionName.equals(ObjectNameUtil.getTransactionName(on)))
+        if (!transactionName.equals(ObjectNameUtil.getTransactionName(on))) {
             throw new IllegalArgumentException(
                     "Transaction name mismatch between expected "
                             + transactionName + " " + "and " + on);
+        }
         ObjectNameUtil.checkType(on, ObjectNameUtil.TYPE_CONFIG_TRANSACTION);
         return new TransactionJMXRegistration(
                 childJMXRegistrator.registerMBean(object, on));
index b973b9272104e22091153cb2721eab891c4b5107..720b7197ea6100b0890ee0fd4a89d5f5de9157bd 100644 (file)
@@ -8,6 +8,7 @@
 package org.opendaylight.controller.config.manager.impl.osgi;
 
 import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.config.api.ValidationException;
 import org.opendaylight.controller.config.api.jmx.CommitStatus;
 import org.opendaylight.controller.config.manager.impl.ConfigRegistryImpl;
 import org.opendaylight.controller.config.spi.ModuleFactory;
@@ -41,7 +42,8 @@ public class BlankTransactionServiceTracker implements ServiceTrackerCustomizer<
     synchronized void blankTransaction() {
         // race condition check: config-persister might push new configuration while server is starting up.
         ConflictingVersionException lastException = null;
-        for (int i = 0; i < 10; i++) {
+        int maxAttempts = 10;
+        for (int i = 0; i < maxAttempts; i++) {
             try {
                 // create transaction
                 boolean blankTransaction = true;
@@ -57,9 +59,13 @@ public class BlankTransactionServiceTracker implements ServiceTrackerCustomizer<
                     Thread.currentThread().interrupt();
                     throw new IllegalStateException(interruptedException);
                 }
+            } catch (ValidationException 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);
             }
         }
-        throw lastException;
+        throw new RuntimeException("Maximal number of attempts reached and still cannot get optimistic lock from " +
+                "config manager",lastException);
     }
 
     @Override
index 2a533ab9a3a6813ad4fed4c4dcfe4a5dbcec2cf6..1e94e5e9c021b1660e02a6d8303333832716ad44 100644 (file)
@@ -53,7 +53,7 @@ public class BundleContextBackedModuleFactoriesResolver implements
             if(factory == null) {
                 throw new NullPointerException("ServiceReference of class" + serviceReference.getClass() + "not found.");
             }
-            StringBuffer errors = new StringBuffer();
+
             String moduleName = factory.getImplementationName();
             if (moduleName == null || moduleName.isEmpty()) {
                 throw new IllegalStateException(
@@ -63,23 +63,17 @@ public class BundleContextBackedModuleFactoriesResolver implements
                 throw new NullPointerException("Bundle context of " + factory + " ModuleFactory not found.");
             }
             logger.debug("Reading factory {} {}", moduleName, factory);
-            String error = null;
+
             Map.Entry<ModuleFactory, BundleContext> conflicting = result.get(moduleName);
             if (conflicting != null) {
-                error = String
-                        .format("Module name is not unique. Found two conflicting factories with same name '%s': " +
-                                "\n\t%s\n\t%s\n", moduleName, conflicting.getKey(), factory);
-
-            }
-
-            if (error == 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);
+                throw new IllegalArgumentException(error);
+            } else {
                 result.put(moduleName, new AbstractMap.SimpleImmutableEntry<>(factory,
                         serviceReference.getBundle().getBundleContext()));
-            } else {
-                errors.append(error);
-            }
-            if (errors.length() > 0) {
-                throw new IllegalArgumentException(errors.toString());
             }
         }
         return result;
index d464cb9006af15b24de4e1e517f57883a893fd47..02cc5ea1e4a01681e9c6b2fe73b435c1a7699db4 100644 (file)
@@ -41,7 +41,7 @@ public class ConfigManagerActivator implements BundleActivator {
     private RuntimeGeneratedMappingServiceActivator mappingServiceActivator;
 
     @Override
-    public void start(BundleContext context) throws Exception {
+    public void start(BundleContext context) {
 
         // track bundles containing YangModuleInfo
         ModuleInfoBundleTracker moduleInfoBundleTracker = new ModuleInfoBundleTracker();
@@ -72,7 +72,7 @@ public class ConfigManagerActivator implements BundleActivator {
         try {
             configRegistryJMXRegistrator.registerToJMX(configRegistry);
         } catch (InstanceAlreadyExistsException e) {
-            throw new RuntimeException("Config Registry was already registered to JMX", e);
+            throw new IllegalStateException("Config Registry was already registered to JMX", e);
         }
 
         ServiceTracker<ModuleFactory, Object> serviceTracker = new ServiceTracker<>(context, ModuleFactory.class,
@@ -81,7 +81,7 @@ public class ConfigManagerActivator implements BundleActivator {
     }
 
     @Override
-    public void stop(BundleContext context) throws Exception {
+    public void stop(BundleContext context) {
         try {
             configRegistry.close();
         } catch (Exception e) {
index 8ba290f30632e10101cc2185367844d29ee73f19..a8fdfda7d7201f9cb00f50f590265e64825d2751 100644 (file)
@@ -20,7 +20,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.InputStream;
-import java.lang.reflect.InvocationTargetException;
 import java.net.URL;
 import java.util.Collection;
 import java.util.LinkedList;
@@ -98,31 +97,26 @@ public final class ModuleInfoBundleTracker implements BundleTrackerCustomizer<Co
             errorMessage = logMessage("Class {} does not implement {} in bundle {}", clazz, YangModelBindingProvider.class, bundle);
             throw new IllegalStateException(errorMessage);
         }
-
+        YangModelBindingProvider instance;
         try {
-            Object instance = clazz.newInstance();
-            Object result = clazz.getMethod(GET_MODULE_INFO_METHOD).invoke(instance);
-
-            if (YangModuleInfo.class.isAssignableFrom(result.getClass()) == false) {
-                errorMessage = logMessage("Error invoking method not found {} in bundle {}, reason {}",
-                        GET_MODULE_INFO_METHOD, bundle, "Not assignable from " + YangModuleInfo.class);
-            } else {
-                return (YangModuleInfo) result;
-            }
-
+            Object instanceObj = clazz.newInstance();
+            instance = YangModelBindingProvider.class.cast(instanceObj);
         } catch (InstantiationException e) {
             errorMessage = logMessage("Could not instantiate {} in bundle {}, reason {}", moduleInfoClass, bundle, e);
+            throw new IllegalStateException(errorMessage, e);
         } catch (IllegalAccessException e) {
             errorMessage = logMessage("Illegal access during instatiation of class {} in bundle {}, reason {}",
                     moduleInfoClass, bundle, e);
-        } catch (NoSuchMethodException e) {
-            errorMessage = logMessage("Method not found {} in bundle {}, reason {}", GET_MODULE_INFO_METHOD, bundle, e);
-        } catch (InvocationTargetException e) {
-            errorMessage = logMessage("Error invoking method {} in bundle {}, reason {}", GET_MODULE_INFO_METHOD,
-                    bundle, e);
+            throw new IllegalStateException(errorMessage, e);
         }
+        try{
+            return instance.getModuleInfo();
+        } catch (NoClassDefFoundError e) {
 
-        throw new IllegalStateException(errorMessage);
+
+            logger.error("Error while executing getModuleInfo on {}", instance, e);
+            throw e;
+        }
     }
 
     private static Class<?> loadClass(String moduleInfoClass, Bundle bundle) {
index 63a66e96eb152c1dfe37caf592f2d0d4778e52c6..123e52f6759e2ec9321c81aa36c6e655ddcb9c7f 100644 (file)
@@ -7,24 +7,27 @@
  */
 package org.opendaylight.controller.config.manager.impl.dependencyresolver;
 
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.reset;
-
-import java.util.Arrays;
-import java.util.List;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.controller.config.api.JmxAttribute;
 import org.opendaylight.controller.config.api.ModuleIdentifier;
 import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.config.manager.impl.ModuleInternalTransactionalInfo;
+import org.opendaylight.controller.config.manager.impl.ModuleInternalInfo;
+import org.opendaylight.controller.config.manager.impl.TransactionIdentifier;
 import org.opendaylight.controller.config.manager.impl.TransactionStatus;
+import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator.TransactionModuleJMXRegistration;
 import org.opendaylight.controller.config.spi.Module;
+import org.opendaylight.controller.config.spi.ModuleFactory;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
 
 public class DependencyResolverManagerTest {
 
@@ -42,7 +45,7 @@ public class DependencyResolverManagerTest {
     public void setUp() {
         transactionStatus = mock(TransactionStatus.class);
         ServiceReferenceReadableRegistry mockedRegistry = mock(ServiceReferenceReadableRegistry.class);
-        tested = new DependencyResolverManager("txName", transactionStatus, mockedRegistry, null);
+        tested = new DependencyResolverManager(new TransactionIdentifier("txName"), transactionStatus, mockedRegistry, null);
         doNothing().when(transactionStatus).checkCommitStarted();
         doNothing().when(transactionStatus).checkNotCommitted();
     }
@@ -87,10 +90,18 @@ public class DependencyResolverManagerTest {
 
     private static void mockGetInstance(DependencyResolverManager tested,
             ModuleIdentifier moduleIdentifier) {
-        ModuleInternalTransactionalInfo mock = mock(ModuleInternalTransactionalInfo.class);
-        doReturn(moduleIdentifier).when(mock).getIdentifier();
-        doReturn(mockedModule()).when(mock).getModule();
-        tested.put(mock);
+
+        ModuleFactory moduleFactory = mock(ModuleFactory.class);
+        ModuleInternalInfo maybeOldInternalInfo = null;
+        TransactionModuleJMXRegistration transactionModuleJMXRegistration = null;
+        boolean isDefaultBean = false;
+
+        tested.put(moduleIdentifier,
+        mockedModule(),
+         moduleFactory,
+         maybeOldInternalInfo,
+         transactionModuleJMXRegistration,
+         isDefaultBean);
     }
 
     private static Module mockedModule() {
index f4ba5ef887e359b9e5a6ab324ac58cc359ae565f..df6dce124339991a50c0016d30dd87cc76168e88 100644 (file)
@@ -7,15 +7,7 @@
  */
 package org.opendaylight.controller.config.manager.testingservices.parallelapsp;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-
-import java.io.Closeable;
-
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.NotThreadSafe;
-import javax.management.ObjectName;
-
+import com.google.common.base.Strings;
 import org.opendaylight.controller.config.api.DependencyResolver;
 import org.opendaylight.controller.config.api.JmxAttribute;
 import org.opendaylight.controller.config.api.ModuleIdentifier;
@@ -26,7 +18,13 @@ import org.opendaylight.controller.config.spi.Module;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Strings;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.NotThreadSafe;
+import javax.management.ObjectName;
+import java.io.Closeable;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
 
 /**
  * Represents service that has dependency to thread pool.
index 441de36db07655558a3f882e7ebbb9ba929e964f..28408abed2fb564c05688302cc0d3b20be0465a9 100644 (file)
@@ -30,7 +30,6 @@ import javax.management.InstanceNotFoundException;
 import javax.management.MBeanException;
 import javax.management.ObjectName;
 import javax.management.ReflectionException;
-import javax.management.RuntimeMBeanException;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
@@ -135,7 +134,7 @@ public class SimpleConfigurationTest extends AbstractConfigTest {
 
     private void testValidation(ConfigTransactionClient transaction)
             throws InstanceAlreadyExistsException, ReflectionException,
-            InstanceNotFoundException, MBeanException {
+            InstanceNotFoundException, MBeanException, ConflictingVersionException {
         ObjectName fixed1names = transaction.createModule(
                 TestingFixedThreadPoolModuleFactory.NAME, fixed1);
         // call validate on config bean
@@ -143,8 +142,8 @@ public class SimpleConfigurationTest extends AbstractConfigTest {
             platformMBeanServer.invoke(fixed1names, "validate", new Object[0],
                     new String[0]);
             fail();
-        } catch (RuntimeMBeanException e) {
-            RuntimeException targetException = e.getTargetException();
+        } catch (MBeanException e) {
+            Exception targetException = e.getTargetException();
             assertNotNull(targetException);
             assertEquals(ValidationException.class, targetException.getClass());
         }
@@ -327,7 +326,7 @@ public class SimpleConfigurationTest extends AbstractConfigTest {
     }
 
     @Test
-    public void testAbort() {
+    public void testAbort() throws InstanceAlreadyExistsException, ValidationException {
         ConfigTransactionJMXClient transaction = configRegistryClient
                 .createTransaction();
         assertEquals(1, configRegistryClient.getOpenConfigs().size());
@@ -337,14 +336,14 @@ public class SimpleConfigurationTest extends AbstractConfigTest {
             transaction.createModule(TestingFixedThreadPoolModuleFactory.NAME,
                     fixed1);
             fail();
-        } catch (Exception e) {
-            assertTrue(e.getCause() instanceof InstanceNotFoundException);
+        } catch (IllegalStateException e) {
+            assertEquals("Configuration was aborted", e.getMessage());
         }
         try {
             transaction.validateConfig();
             fail();
-        } catch (Exception e) {
-            assertTrue(e.getCause() instanceof InstanceNotFoundException);
+        } catch (IllegalStateException e) {
+            assertEquals("Configuration was aborted", e.getMessage());
         }
         assertEquals(0, configRegistryClient.getOpenConfigs().size());
     }
index 42c9105c057ae1b575537297c51f14ad68f07a19..7fb622460fad852e5012fed6e8929837a03cf1e6 100644 (file)
@@ -5,7 +5,7 @@
   <parent>
     <groupId>org.opendaylight.controller</groupId>
     <artifactId>config-subsystem</artifactId>
-    <version>0.2.4-SNAPSHOT</version>
+    <version>0.2.5-SNAPSHOT</version>
   </parent>
 
   <artifactId>config-module-archetype</artifactId>
index 403ee82b8ed22455e93d3cbcee176a5fb6860466..f800e369851467210d63caf18d2c511126377a94 100644 (file)
@@ -3,7 +3,7 @@
     <parent>
         <artifactId>config-subsystem</artifactId>
         <groupId>org.opendaylight.controller</groupId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
         <relativePath>..</relativePath>
     </parent>
     <artifactId>config-persister-api</artifactId>
index 919fd13fc201bfa4957965db7b64dd20631d3422..86b8c4d947f83649ea082fd2331d23522c5cac85 100644 (file)
@@ -4,7 +4,7 @@
     <parent>
         <artifactId>config-subsystem</artifactId>
         <groupId>org.opendaylight.controller</groupId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
         <relativePath>..</relativePath>
     </parent>
     <artifactId>config-persister-directory-adapter</artifactId>
index 92f7e27788884cae7f39ba969f62625a5eecd718..5e556c07a9dbf630ead635b5263d537e24fc50ef 100644 (file)
@@ -4,7 +4,7 @@
     <parent>
         <artifactId>config-subsystem</artifactId>
         <groupId>org.opendaylight.controller</groupId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
         <relativePath>..</relativePath>
     </parent>
     <artifactId>config-persister-directory-autodetect-adapter</artifactId>
index 2c5d2359a0633ab596d3920ac76b8ff29870a97b..75188fe9b37aa44632158d9e1f3f456e4be2af37 100644 (file)
@@ -4,7 +4,7 @@
     <parent>
         <artifactId>config-subsystem</artifactId>
         <groupId>org.opendaylight.controller</groupId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
         <relativePath>..</relativePath>
     </parent>
     <artifactId>config-persister-directory-xml-adapter</artifactId>
index 4681b3b710288d0b91d8c9575e008798e29fda79..a8ea93e71bf26b2a597a7b3a25c8f91e51845fbe 100644 (file)
@@ -4,7 +4,7 @@
     <parent>
         <artifactId>config-subsystem</artifactId>
         <groupId>org.opendaylight.controller</groupId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
         <relativePath>..</relativePath>
     </parent>
     <artifactId>config-persister-file-adapter</artifactId>
index 6fa496d92ea7150a06d7f9067f5c1d323f8f3a86..dd2079550e1203714c369f83f596616ee806fc96 100644 (file)
@@ -4,7 +4,7 @@
     <parent>
         <artifactId>config-subsystem</artifactId>
         <groupId>org.opendaylight.controller</groupId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
         <relativePath>..</relativePath>
     </parent>
     <artifactId>config-persister-file-xml-adapter</artifactId>
index 0bc1ef6e769a89ac7a2559d1681d9fdfd510dccf..e382c338716bc47b4bf7b2657cec526b1835d7f9 100644 (file)
@@ -4,7 +4,7 @@
     <parent>
         <groupId>org.opendaylight.controller</groupId>
         <artifactId>config-subsystem</artifactId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>config-plugin-parent</artifactId>
@@ -16,7 +16,6 @@
 
     <properties>
         <jmxGeneratorPath>${project.build.directory}/generated-sources/config</jmxGeneratorPath>
-        <config.version>0.2.4-SNAPSHOT</config.version>
     </properties>
 
     <build>
index 6a50ee843a98fc903e3bb1ab00052e4a162726f9..9b866efb13d0bcafe3c225d590871dda671082ec 100644 (file)
@@ -3,7 +3,7 @@
     <parent>
         <artifactId>config-subsystem</artifactId>
         <groupId>org.opendaylight.controller</groupId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
         <relativePath>..</relativePath>
     </parent>
     <artifactId>config-util</artifactId>
index 3583dafd0d46c3fcedb070e00b8cc175255bc4c8..4adc0d9364e3392969c0c771edc4fd5ae41cdaf1 100644 (file)
@@ -7,24 +7,23 @@
  */
 package org.opendaylight.controller.config.util;
 
-import java.util.Map;
-import java.util.Set;
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.config.api.ValidationException;
+import org.opendaylight.controller.config.api.jmx.CommitStatus;
+import org.opendaylight.controller.config.api.jmx.ConfigRegistryMXBean;
+import org.opendaylight.controller.config.api.jmx.ConfigTransactionControllerMXBean;
+import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
 
 import javax.management.Attribute;
 import javax.management.InstanceAlreadyExistsException;
 import javax.management.InstanceNotFoundException;
 import javax.management.JMException;
 import javax.management.JMX;
+import javax.management.MBeanException;
 import javax.management.MBeanServer;
 import javax.management.ObjectName;
-import javax.management.RuntimeMBeanException;
-
-import org.opendaylight.controller.config.api.ConflictingVersionException;
-import org.opendaylight.controller.config.api.ValidationException;
-import org.opendaylight.controller.config.api.jmx.CommitStatus;
-import org.opendaylight.controller.config.api.jmx.ConfigRegistryMXBean;
-import org.opendaylight.controller.config.api.jmx.ConfigTransactionControllerMXBean;
-import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import java.util.Map;
+import java.util.Set;
 
 public class ConfigTransactionJMXClient implements ConfigTransactionClient {
     private final ConfigRegistryMXBean configRegistryMXBeanProxy;
@@ -234,10 +233,15 @@ public class ConfigTransactionJMXClient implements ConfigTransactionClient {
             throws ValidationException {
         try {
             configMBeanServer.invoke(configBeanON, "validate", null, null);
+        } catch (MBeanException e) {
+            Exception targetException = e.getTargetException();
+            if (targetException instanceof ValidationException){
+                throw (ValidationException) targetException;
+            } else {
+                throw new RuntimeException(e);
+            }
         } catch (JMException e) {
             throw new RuntimeException(e);
-        } catch (RuntimeMBeanException e) {
-            throw e.getTargetException();
         }
     }
 
index 4e0cfaada67173ad6d5b733e8b30661df3280a10..fbebda526acb82e80ef3a3fa82595dbb4390613a 100644 (file)
@@ -5,7 +5,7 @@
     <parent>
         <groupId>org.opendaylight.controller</groupId>
         <artifactId>config-plugin-parent</artifactId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
         <relativePath>../config-plugin-parent</relativePath>
     </parent>
     <artifactId>logback-config</artifactId>
index eeb8289e86196665cd971ce932112779fee04bb7..e543f752e17b44ee6ab2a1851b54168fccb422d6 100644 (file)
@@ -7,24 +7,19 @@
  */
 package org.opendaylight.controller.config.yang.logback.config;
 
-import static org.junit.Assert.assertEquals;
-
-import java.io.File;
-import java.io.IOException;
-import java.lang.management.ManagementFactory;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.InstanceNotFoundException;
-import javax.management.JMX;
-import javax.management.MalformedObjectNameException;
-import javax.management.ObjectName;
-
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
+import ch.qos.logback.classic.joran.JoranConfigurator;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.joran.spi.JoranException;
+import ch.qos.logback.core.rolling.FixedWindowRollingPolicy;
+import ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy;
+import com.google.common.collect.Lists;
 import org.apache.commons.io.FileUtils;
 import org.junit.Before;
 import org.junit.Test;
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.config.api.ValidationException;
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
 import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
 import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
@@ -32,15 +27,19 @@ import org.opendaylight.controller.config.util.ConfigTransactionClient;
 import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
 import org.slf4j.LoggerFactory;
 
-import ch.qos.logback.classic.LoggerContext;
-import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
-import ch.qos.logback.classic.joran.JoranConfigurator;
-import ch.qos.logback.classic.spi.ILoggingEvent;
-import ch.qos.logback.core.joran.spi.JoranException;
-import ch.qos.logback.core.rolling.FixedWindowRollingPolicy;
-import ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.JMX;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import java.io.File;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 
-import com.google.common.collect.Lists;
+import static org.junit.Assert.assertEquals;
 
 public class LogbackModuleWithInitialConfigurationTest extends AbstractConfigTest {
 
@@ -145,7 +144,7 @@ public class LogbackModuleWithInitialConfigurationTest extends AbstractConfigTes
     }
 
     public ObjectName createBeans() throws JoranException, InstanceAlreadyExistsException, IOException,
-            MalformedObjectNameException, InstanceNotFoundException {
+            MalformedObjectNameException, InstanceNotFoundException, ValidationException, ConflictingVersionException {
 
         LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
 
index 8718f8a9ce3121c260d41555f8ff509849c09b97..814965981226aa2ee71fa2184843ad741cc7d414 100644 (file)
@@ -7,32 +7,31 @@
  */
 package org.opendaylight.controller.config.yang.logback.config;
 
-import static org.junit.Assert.assertEquals;
-
-import java.io.File;
-import java.io.IOException;
-import java.lang.management.ManagementFactory;
-import java.util.List;
-
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.InstanceNotFoundException;
-import javax.management.JMX;
-import javax.management.MalformedObjectNameException;
-import javax.management.ObjectName;
-
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.joran.JoranConfigurator;
+import ch.qos.logback.core.joran.spi.JoranException;
+import com.google.common.collect.Lists;
 import org.apache.commons.io.FileUtils;
 import org.junit.Before;
 import org.junit.Test;
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.config.api.ValidationException;
 import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
 import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
 import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
 import org.slf4j.LoggerFactory;
 
-import ch.qos.logback.classic.LoggerContext;
-import ch.qos.logback.classic.joran.JoranConfigurator;
-import ch.qos.logback.core.joran.spi.JoranException;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.JMX;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import java.io.File;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.util.List;
 
-import com.google.common.collect.Lists;
+import static org.junit.Assert.assertEquals;
 
 public class LogbackWithXmlConfigModuleTest extends AbstractConfigTest {
 
@@ -61,7 +60,7 @@ public class LogbackWithXmlConfigModuleTest extends AbstractConfigTest {
      * @throws MalformedObjectNameException
      */
     @Test
-    public void test() throws InstanceAlreadyExistsException, InstanceNotFoundException, MalformedObjectNameException {
+    public void test() throws InstanceAlreadyExistsException, InstanceNotFoundException, MalformedObjectNameException, ValidationException, ConflictingVersionException {
 
         ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
         ObjectName nameRetrieved = transaction.lookupConfigBean(factory.getImplementationName(), LogbackModuleFactory.INSTANCE_NAME);
@@ -106,7 +105,7 @@ public class LogbackWithXmlConfigModuleTest extends AbstractConfigTest {
      */
     @Test
     public void testAddNewLogger() throws InstanceAlreadyExistsException, InstanceNotFoundException,
-            MalformedObjectNameException {
+            MalformedObjectNameException, ValidationException, ConflictingVersionException {
 
         ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
         ObjectName nameRetrieved = transaction.lookupConfigBean(factory.getImplementationName(), LogbackModuleFactory.INSTANCE_NAME);
index fd099b3242ad1e88c686eb649e479ced0297c17e..2a53e445f5764ac39266ef548d4b59963ecbb21f 100644 (file)
@@ -4,7 +4,7 @@
   <parent>
     <groupId>org.opendaylight.controller</groupId>
         <artifactId>config-plugin-parent</artifactId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
         <relativePath>../config-plugin-parent</relativePath>
   </parent>
   <modelVersion>4.0.0</modelVersion>
index 88afa1315545df59131bd13b66a5abe8e8957e19..452c5ac71515d9e3bdfc64ee4d1787afa0328d27 100644 (file)
@@ -4,7 +4,7 @@
    <parent>
       <groupId>org.opendaylight.controller</groupId>
         <artifactId>config-plugin-parent</artifactId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
         <relativePath>../config-plugin-parent</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>
diff --git a/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/AutoCloseableEventExecutor.java b/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/AutoCloseableEventExecutor.java
new file mode 100644 (file)
index 0000000..69ea51f
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.config.yang.netty.eventexecutor;
+
+import com.google.common.reflect.AbstractInvocationHandler;
+import com.google.common.reflect.Reflection;
+import io.netty.util.concurrent.EventExecutor;
+
+import java.lang.reflect.Method;
+import java.util.concurrent.TimeUnit;
+
+public interface AutoCloseableEventExecutor extends EventExecutor, AutoCloseable {
+
+
+    public static class CloseableEventExecutorMixin implements AutoCloseable {
+        public static final int DEFAULT_SHUTDOWN_SECONDS = 1;
+        private final EventExecutor eventExecutor;
+
+        public CloseableEventExecutorMixin(EventExecutor eventExecutor) {
+            this.eventExecutor = eventExecutor;
+        }
+
+        @Override
+        public void close() {
+            eventExecutor.shutdownGracefully(0, DEFAULT_SHUTDOWN_SECONDS, TimeUnit.SECONDS);
+        }
+
+
+        public static AutoCloseable createCloseableProxy(final EventExecutor eventExecutor) {
+            final CloseableEventExecutorMixin closeableGlobalEventExecutorMixin =
+                    new CloseableEventExecutorMixin(eventExecutor);
+            return Reflection.newProxy(AutoCloseableEventExecutor.class, new AbstractInvocationHandler() {
+                @Override
+                protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
+                    if (method.getName().equals("close")) {
+                        closeableGlobalEventExecutorMixin.close();
+                        return null;
+                    } else {
+                        return method.invoke(eventExecutor, args);
+                    }
+                }
+            });
+        }
+
+
+    }
+}
\ No newline at end of file
index 2c4c2117840e89f74e98f1e2ef94e27a56f72424..8751a80b8d163838b08e8b014abc5371be777978 100644 (file)
  */
 package org.opendaylight.controller.config.yang.netty.eventexecutor;
 
-import com.google.common.reflect.AbstractInvocationHandler;
-import com.google.common.reflect.Reflection;
 import io.netty.util.concurrent.EventExecutor;
 import io.netty.util.concurrent.GlobalEventExecutor;
-
-import java.lang.reflect.Method;
-import java.util.concurrent.TimeUnit;
+import org.opendaylight.controller.config.yang.netty.eventexecutor.AutoCloseableEventExecutor.CloseableEventExecutorMixin;
 
 public final class GlobalEventExecutorModule extends
         org.opendaylight.controller.config.yang.netty.eventexecutor.AbstractGlobalEventExecutorModule {
@@ -46,35 +42,10 @@ public final class GlobalEventExecutorModule extends
 
     @Override
     public java.lang.AutoCloseable createInstance() {
-        final CloseableGlobalEventExecutorMixin closeableGlobalEventExecutorMixin =
-                new CloseableGlobalEventExecutorMixin(GlobalEventExecutor.INSTANCE);
-        return Reflection.newProxy(AutoCloseableEventExecutor.class, new AbstractInvocationHandler() {
-            @Override
-            protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
-                if (method.getName().equals("close")) {
-                    closeableGlobalEventExecutorMixin.close();
-                    return null;
-                } else {
-                    return method.invoke(GlobalEventExecutor.INSTANCE, args);
-                }
-            }
-        });
+        EventExecutor eventExecutor = GlobalEventExecutor.INSTANCE;
+        return CloseableEventExecutorMixin.createCloseableProxy(eventExecutor);
     }
 
-    public static interface AutoCloseableEventExecutor extends EventExecutor, AutoCloseable {
-
-    }
 
-    public static class CloseableGlobalEventExecutorMixin implements AutoCloseable {
-        private final GlobalEventExecutor eventExecutor;
 
-        public CloseableGlobalEventExecutorMixin(GlobalEventExecutor eventExecutor) {
-            this.eventExecutor = eventExecutor;
-        }
-
-        @Override
-        public void close() {
-            eventExecutor.shutdownGracefully(0, 1, TimeUnit.SECONDS);
-        }
-    }
 }
diff --git a/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/ImmediateEventExecutorModule.java b/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/ImmediateEventExecutorModule.java
new file mode 100644 (file)
index 0000000..27ca63f
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.config.yang.netty.eventexecutor;
+
+import io.netty.util.concurrent.EventExecutor;
+import io.netty.util.concurrent.ImmediateEventExecutor;
+import org.opendaylight.controller.config.yang.netty.eventexecutor.AutoCloseableEventExecutor.CloseableEventExecutorMixin;
+
+public final class ImmediateEventExecutorModule extends org.opendaylight.controller.config.yang.netty.eventexecutor.AbstractImmediateEventExecutorModule {
+
+    public ImmediateEventExecutorModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public ImmediateEventExecutorModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+                                        ImmediateEventExecutorModule oldModule, java.lang.AutoCloseable oldInstance) {
+
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    protected void customValidation() {
+        // Add custom validation for module attributes here.
+    }
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+        EventExecutor eventExecutor = ImmediateEventExecutor.INSTANCE;
+        return CloseableEventExecutorMixin.createCloseableProxy(eventExecutor);
+    }
+}
diff --git a/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/ImmediateEventExecutorModuleFactory.java b/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/ImmediateEventExecutorModuleFactory.java
new file mode 100644 (file)
index 0000000..b3ec67b
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.config.yang.netty.eventexecutor;
+
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.osgi.framework.BundleContext;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+public class ImmediateEventExecutorModuleFactory extends org.opendaylight.controller.config.yang.netty.eventexecutor.AbstractImmediateEventExecutorModuleFactory {
+    public static final String SINGLETON_NAME = "singleton";
+
+    @Override
+    public ImmediateEventExecutorModule instantiateModule(String instanceName, DependencyResolver dependencyResolver, ImmediateEventExecutorModule oldModule, AutoCloseable oldInstance, BundleContext bundleContext) {
+        checkArgument(SINGLETON_NAME.equals(instanceName), "Illegal instance name '" + instanceName + "', only allowed name is " + SINGLETON_NAME);
+        return super.instantiateModule(instanceName, dependencyResolver, oldModule, oldInstance, bundleContext);
+    }
+
+    @Override
+    public ImmediateEventExecutorModule instantiateModule(String instanceName, DependencyResolver dependencyResolver, BundleContext bundleContext) {
+        checkArgument(SINGLETON_NAME.equals(instanceName), "Illegal instance name '" + instanceName + "', only allowed name is " + SINGLETON_NAME);
+        return super.instantiateModule(instanceName, dependencyResolver, bundleContext);
+    }
+}
index e9d1da3f2dd6de1f0c80701a68b21227fadd8c72..8d812adc4d1231f4507c19a70c9d5df4a28e72d0 100644 (file)
@@ -36,7 +36,18 @@ module netty-event-executor {
     augment "/config:modules/config:module/config:configuration" {
         case netty-global-event-executor {
             when "/config:modules/config:module/config:type = 'netty-global-event-executor'";
+        }
+    }
 
+    identity netty-immediate-event-executor {
+        base config:module-type;
+        config:provided-service netty:netty-event-executor;
+        config:java-name-prefix ImmediateEventExecutor;
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case netty-immediate-event-executor {
+            when "/config:modules/config:module/config:type = 'netty-immediate-event-executor'";
         }
     }
 }
index 172fe7f1fcbb8fbf9dfbca593e67f4a2d0b00e56..54143355f451c85552773492751b5643bb591a06 100644 (file)
@@ -5,7 +5,7 @@
     <parent>
         <groupId>org.opendaylight.controller</groupId>
         <artifactId>config-plugin-parent</artifactId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
         <relativePath>../config-plugin-parent</relativePath>
     </parent>
 
index 9d3b5505cefbf8cb5d2d3a5689ea50e03b033fc1..a056a1c126e0fada063705b34404fc0414f2794b 100644 (file)
@@ -4,7 +4,7 @@
    <parent>
       <groupId>org.opendaylight.controller</groupId>
         <artifactId>config-plugin-parent</artifactId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
         <relativePath>../config-plugin-parent</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>
index 3474740ca178e659abd6a52e7ad78febb9eab556..4ec7e2f64b6143560c731a8f8f1bcd56602cff3f 100644 (file)
@@ -10,7 +10,7 @@
     </parent>
 
 
-    <version>0.2.4-SNAPSHOT</version>
+    <version>0.2.5-SNAPSHOT</version>
     <artifactId>config-subsystem</artifactId>
     <packaging>pom</packaging>
     <name>${project.artifactId}</name>
@@ -68,7 +68,6 @@
         <jacoco.version>0.6.2.201302030002</jacoco.version>
         <slf4j.version>1.7.2</slf4j.version>
         <salGeneratorPath>${project.build.directory}/generated-sources/sal</salGeneratorPath>
-        <config.version>0.2.4-SNAPSHOT</config.version>
     </properties>
 
     <dependencies>
index 99a88fe209b6d0940b1c7c3eb38cf552315e13b3..1e14bc496188bbf6a1d66363e931518b5be19460 100644 (file)
@@ -3,7 +3,7 @@
     <parent>
         <artifactId>config-plugin-parent</artifactId>
         <groupId>org.opendaylight.controller</groupId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
         <relativePath>../config-plugin-parent</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
index fa661b4ab8c11c275ad0a4a981acd4619ff82819..8cf164d2a5660bd7b3ab6e12a26a15684e03f042 100644 (file)
@@ -3,7 +3,7 @@
     <parent>
         <artifactId>config-plugin-parent</artifactId>
         <groupId>org.opendaylight.controller</groupId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
         <relativePath>../config-plugin-parent</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
index d1abe08d52b64453ee038a8a8b053e80ae08c586..d4a3160b89bf5da79c9b1407aa5bd3242f23b745 100644 (file)
@@ -11,6 +11,8 @@ import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.config.api.ValidationException;
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
 import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
 import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
@@ -92,7 +94,7 @@ public class ShutdownTest extends AbstractConfigTest {
         shutdownViaRuntimeJMX(secret);
     }
 
-    private void setSecret(String secret) throws InstanceNotFoundException {
+    private void setSecret(String secret) throws InstanceNotFoundException, ValidationException, ConflictingVersionException {
         ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
         ObjectName on = transaction.lookupConfigBean(NAME, NAME);
         ShutdownModuleMXBean proxy = transaction.newMXBeanProxy(on, ShutdownModuleMXBean.class);
index 2f5e35c26d85dbcbc5ec4ad3cace430ffb2ff5f8..7e45fa3c6bb52b9d0486f96652479fa3bf4f27de 100644 (file)
@@ -4,7 +4,7 @@
    <parent>
       <groupId>org.opendaylight.controller</groupId>
         <artifactId>config-plugin-parent</artifactId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
         <relativePath>../config-plugin-parent</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>
index 08f1d554f6c4e515356163a5a99f2ea9efc35713..fcedbd85f16e89426753e03ea703feb4a28ea0dd 100644 (file)
@@ -4,7 +4,7 @@
    <parent>
       <groupId>org.opendaylight.controller</groupId>
         <artifactId>config-plugin-parent</artifactId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
         <relativePath>../config-plugin-parent</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>
index a0ef5c27358cfa6684be96e55875b7778ac343b5..f081b7bd387b41933f0aaff473b24a57855d0d1b 100644 (file)
@@ -4,7 +4,7 @@
     <parent>
         <artifactId>config-subsystem</artifactId>
         <groupId>org.opendaylight.controller</groupId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
     </parent>
 
     <artifactId>yang-jmx-generator-it</artifactId>
index f6d1c88c83b0c807b858b188eb7c57165e3df8d9..a8119b81ae21361d657e845d9fb2bc8a95b5c242 100644 (file)
@@ -3,7 +3,7 @@
     <parent>
         <artifactId>config-subsystem</artifactId>
         <groupId>org.opendaylight.controller</groupId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
         <relativePath>..</relativePath>
     </parent>
     <artifactId>yang-jmx-generator-plugin</artifactId>
index d6d3893bebdd54113a549bf9692e3851f7545af8..37d5e6bd3fcae0259ae06079d1c909e016b8525f 100644 (file)
@@ -53,7 +53,7 @@ public class FtlFilePersister {
                         ftlFile.getFtlTempleteLocation());
                 try {
                     template.process(ftlFile, writer);
-                } catch (Throwable e) {
+                } catch (Exception e) {
                     throw new IllegalStateException(
                             "Template error while generating " + ftlFile, e);
                 }
index b6e89cb92ea46aa80bd13167dddfc3ccafada071..92ce0feccd177a5a8ae7c952b0804409fa2d3da6 100644 (file)
@@ -4,7 +4,7 @@
     <parent>
         <artifactId>config-subsystem</artifactId>
         <groupId>org.opendaylight.controller</groupId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
     </parent>
 
     <artifactId>yang-jmx-generator</artifactId>
index 4a9d5512d3fc024892d641215572b566c51b8d6c..676c8eca6ec6f9a903c34aeebd69d9c8abbeae07 100644 (file)
@@ -195,16 +195,17 @@ final class ModuleMXBeanEntryBuilder {
                 boolean providedServiceWasSet = false;
                 for (UnknownSchemaNode unknownNode : id.getUnknownSchemaNodes()) {
                     // TODO: test this
-                    if (ConfigConstants.PROVIDED_SERVICE_EXTENSION_QNAME.equals(unknownNode.getNodeType())) {
-                        // no op: 0 or more provided identities are allowed
-                    } else if (ConfigConstants.JAVA_NAME_PREFIX_EXTENSION_QNAME.equals(unknownNode.getNodeType())) {
+                    boolean unknownNodeIsProvidedServiceExtension = ConfigConstants.PROVIDED_SERVICE_EXTENSION_QNAME.equals(unknownNode.getNodeType());
+                    // true => no op: 0 or more provided identities are allowed
+
+                    if (ConfigConstants.JAVA_NAME_PREFIX_EXTENSION_QNAME.equals(unknownNode.getNodeType())) {
                         // 0..1 allowed
                         checkState(
                                 providedServiceWasSet == false,
                                 format("More than one language extension %s is not allowed here: %s",
                                         ConfigConstants.JAVA_NAME_PREFIX_EXTENSION_QNAME, id));
                         providedServiceWasSet = true;
-                    } else {
+                    } else if (unknownNodeIsProvidedServiceExtension == false) {
                         throw new IllegalStateException("Unexpected language extension " + unknownNode.getNodeType());
                     }
                 }
index 84300cb81d1000571e5fb52070ebefa91c3c33e4..cbeb5c3b297415bacf1a74596abbbf8d4fb9d207 100644 (file)
@@ -25,7 +25,9 @@ import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 import javax.management.openmbean.CompositeType;
 import javax.management.openmbean.OpenDataException;
 import javax.management.openmbean.OpenType;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
@@ -208,22 +210,20 @@ public class TOAttribute extends AbstractAttribute implements TypedAttribute {
 
     @Override
     public CompositeType getOpenType() {
-        String description = getNullableDescription() == null ? getAttributeYangName()
-                : getNullableDescription();
-        final String[] itemNames = new String[yangNameToAttributeMap.keySet()
-                .size()];
-        String[] itemDescriptions = itemNames;
-        FunctionImpl functionImpl = new FunctionImpl(itemNames);
+        String description = getNullableDescription() == null ? getAttributeYangName() : getNullableDescription();
+
+        FunctionImpl functionImpl = new FunctionImpl();
         Map<String, AttributeIfc> jmxPropertiesToTypesMap = getJmxPropertiesToTypesMap();
         OpenType<?>[] itemTypes = Collections2.transform(
                 jmxPropertiesToTypesMap.entrySet(), functionImpl).toArray(
                 new OpenType<?>[] {});
+        String[] itemNames = functionImpl.getItemNames();
         try {
             // TODO add package name to create fully qualified name for this
             // type
             CompositeType compositeType = new CompositeType(
                     getUpperCaseCammelCase(), description, itemNames,
-                    itemDescriptions, itemTypes);
+                    itemNames, itemTypes);
             return compositeType;
         } catch (OpenDataException e) {
             throw new RuntimeException("Unable to create CompositeType for "
@@ -235,20 +235,20 @@ public class TOAttribute extends AbstractAttribute implements TypedAttribute {
         return packageName;
     }
 
-    private static final class FunctionImpl implements
-            Function<Entry<String, AttributeIfc>, OpenType<?>> {
-        private final String[] itemNames;
-        int i = 0;
+}
 
-        private FunctionImpl(String[] itemNames) {
-            this.itemNames = itemNames;
-        }
+class FunctionImpl implements
+        Function<Entry<String, AttributeIfc>, OpenType<?>> {
+    private final List<String> itemNames = new ArrayList<>();
 
-        @Override
-        public OpenType<?> apply(Entry<String, AttributeIfc> input) {
-            AttributeIfc innerType = input.getValue();
-            itemNames[i++] = input.getKey();
-            return innerType.getOpenType();
-        }
+    @Override
+    public OpenType<?> apply(Entry<String, AttributeIfc> input) {
+        AttributeIfc innerType = input.getValue();
+        itemNames.add(input.getKey());
+        return innerType.getOpenType();
+    }
+
+    public String[] getItemNames(){
+        return itemNames.toArray(new String[itemNames.size()]);
     }
 }
index b071025c1a0b172c122687181ae90ed41505ed5f..dfd9adb23f11e942f565a616c6ac46bf33fd63f7 100644 (file)
@@ -3,7 +3,7 @@
     <parent>
         <artifactId>config-subsystem</artifactId>
         <groupId>org.opendaylight.controller</groupId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
         <relativePath>..</relativePath>
     </parent>
     <artifactId>yang-store-api</artifactId>
index c4ac8305914cb0fbf530492f39dfa7b45b3cc045..8a88cd04f96d7f0516de01f485df54eb4fb0f9ed 100644 (file)
@@ -3,7 +3,7 @@
     <parent>
         <artifactId>config-subsystem</artifactId>
         <groupId>org.opendaylight.controller</groupId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
         <relativePath>..</relativePath>
     </parent>
     <artifactId>yang-store-impl</artifactId>
index fe7358ee900eb10d29862b195d7e7b670fadd873..0b4fc8b1b534209f112faeacdd564c12ecc089ad 100644 (file)
@@ -3,7 +3,7 @@
     <parent>
         <groupId>org.opendaylight.controller</groupId>
         <artifactId>config-plugin-parent</artifactId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
         <relativePath>../config-plugin-parent</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
index 9037ff0c0f4dd9e23835b8d91e62e0ebdf811223..6caee4108ae8d93ff49d265e61ac89fdda093569 100644 (file)
@@ -5,7 +5,7 @@
     <parent>
         <groupId>org.opendaylight.controller</groupId>
         <artifactId>config-plugin-parent</artifactId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
         <relativePath>../config-plugin-parent</relativePath>
     </parent>
 
index b000f11e4e352f0d76f8d6cf7e55449863951071..398bba99bde6b3923028f9e20d88582a33c96454 100644 (file)
@@ -31,15 +31,16 @@ public final class IdentityTestModule extends org.opendaylight.controller.config
 
     @Override
     public java.lang.AutoCloseable createInstance() {
-        System.err.println(getAfi());
-        System.err.println(getAfiIdentity());
+        org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(getClass());
+        logger.info("Afi: {}", getAfi());
+        logger.info("Afi class: {}", getAfiIdentity());
 
-        getAfiIdentity();
         for (Identities identities : getIdentities()) {
-            identities.resolveAfi();
-            identities.resolveSafi();
+            logger.info("Identities Afi class: {}", identities.resolveAfi());
+            logger.info("Identities Safi class: {}", identities.resolveSafi());
+
         }
-        getIdentitiesContainer().resolveAfi();
+        logger.info("IdentityContainer Afi class: {}", getIdentitiesContainer().resolveAfi());
 
         return new AutoCloseable() {
             @Override
index a81159ea24c6fc0f29b2e1a9e7684c069f2db4bc..7fa0c10eb2c570bd91c47f924ecc26087d4e360e 100644 (file)
@@ -1,12 +1,13 @@
-        System.err.println(getAfi());
-        System.err.println(getAfiIdentity());
+        org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(getClass());
+        logger.info("Afi: {}", getAfi());
+        logger.info("Afi class: {}", getAfiIdentity());
 
-        getAfiIdentity();
         for (Identities identities : getIdentities()) {
-            identities.resolveAfi();
-            identities.resolveSafi();
+            logger.info("Identities Afi class: {}", identities.resolveAfi());
+            logger.info("Identities Safi class: {}", identities.resolveSafi());
+
         }
-        getIdentitiesContainer().resolveAfi();
+        logger.info("IdentityContainer Afi class: {}", getIdentitiesContainer().resolveAfi());
 
         return new AutoCloseable() {
             @Override
index 90e3b03ae4b7168fcc51a70a32499caca2086515..64f2c877f7ea60f2e87f13bb9d4b173a11d7a16d 100755 (executable)
@@ -59,7 +59,7 @@ else
 fi
 
 function usage {
-    echo "Usage: $0 [-jmx] [-jmxport <num>] [-debug] [-debugsuspend] [-debugport <num>] [-start [<console port>]] [-stop] [-status] [-console] [-help] [<other args will automatically be used for the JVM>]"
+    echo "Usage: $0 [-jmx] [-jmxport <num>] [-debug] [-debugsuspend] [-debugport <num>] [-start [<console port>]] [-stop] [-status] [-console] [-help] [-agentpath:<path to lib>] [<other args will automatically be used for the JVM>]"
     exit 1
 }
 
@@ -83,6 +83,7 @@ statusdaemon=0
 consolestart=1
 dohelp=0
 extraJVMOpts=""
+agentPath=""
 unknown_option=0
 while true ; do
     case "$1" in
@@ -98,6 +99,7 @@ while true ; do
         -help) dohelp=1; shift;;
         -D*) extraJVMOpts="${extraJVMOpts} $1"; shift;;
         -X*) extraJVMOpts="${extraJVMOpts} $1"; shift;;
+        -agentpath:*) agentPath="$1"; shift;;
         "") break ;;
         *) echo "Unknown option $1"; unknown_option=1; shift ;;
     esac
@@ -209,6 +211,7 @@ if [ "${startdaemon}" -eq 1 ]; then
         exit -1
     fi
     $JAVA_HOME/bin/java ${extraJVMOpts} \
+        ${agentPath} \
         -Djava.io.tmpdir="${iotmpdir}/work/tmp" \
         -Dosgi.install.area="${bdir}" \
         -Dosgi.configuration.area="${confarea}/configuration" \
@@ -227,6 +230,7 @@ elif [ "${consolestart}" -eq 1 ]; then
         exit -1
     fi
     $JAVA_HOME/bin/java ${extraJVMOpts} \
+        ${agentPath} \
         -Djava.io.tmpdir="${iotmpdir}/work/tmp" \
         -Dosgi.install.area="${bdir}" \
         -Dosgi.configuration.area="${confarea}/configuration" \
index b94103fb1c7c9233bb417e93cc74d42bbef498e7..bdbf7acd5f6781fe153fe35421bbfe3aec6dbbd8 100644 (file)
@@ -1121,7 +1121,10 @@ public class ForwardingRulesManager implements
             List<FlowEntryInstall> list = new ArrayList<FlowEntryInstall>(groupFlows.get(groupName));
             toBeRemoved = list.size();
             for (FlowEntryInstall entry : list) {
-                Status status = this.removeEntry(entry.getOriginal(), false);
+                // since this is the entry that was stored in groupFlows
+                // it is already validated and merged
+                // so can call removeEntryInternal directly
+                Status status = this.removeEntryInternal(entry, false);
                 if (status.isSuccess()) {
                     toBeRemoved -= 1;
                 } else {
index 84508ca03e99475b7a95fcc0a0e676082e227f04..01d75acfe6332b3e6574683ad49736efdf58655f 100644 (file)
@@ -8,10 +8,8 @@
 package org.opendaylight.controller.sal.compatibility.adsal;
 
 import java.math.BigInteger;
-import java.util.concurrent.Future;
 
 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
-import org.opendaylight.controller.sal.common.util.Futures;
 import org.opendaylight.controller.sal.common.util.Rpcs;
 import org.opendaylight.controller.sal.compatibility.InventoryMapping;
 import org.opendaylight.controller.sal.compatibility.ToSalConversionsUtils;
@@ -37,6 +35,9 @@ import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
 public class FlowServiceAdapter implements SalFlowService, IFlowProgrammerListener {
 
     private static final Logger LOG = LoggerFactory.getLogger(FlowServiceAdapter.class);
@@ -59,7 +60,7 @@ public class FlowServiceAdapter implements SalFlowService, IFlowProgrammerListen
     }
 
     @Override
-    public Future<RpcResult<AddFlowOutput>> addFlow(AddFlowInput input) {
+    public ListenableFuture<RpcResult<AddFlowOutput>> addFlow(AddFlowInput input) {
 
         Flow flow = ToSalConversionsUtils.toFlow(input, null);
         @SuppressWarnings("unchecked")
@@ -73,7 +74,7 @@ public class FlowServiceAdapter implements SalFlowService, IFlowProgrammerListen
     }
 
     @Override
-    public Future<RpcResult<RemoveFlowOutput>> removeFlow(RemoveFlowInput input) {
+    public ListenableFuture<RpcResult<RemoveFlowOutput>> removeFlow(RemoveFlowInput input) {
 
         Flow flow = ToSalConversionsUtils.toFlow(input, null);
         @SuppressWarnings("unchecked")
@@ -88,7 +89,7 @@ public class FlowServiceAdapter implements SalFlowService, IFlowProgrammerListen
     }
 
     @Override
-    public Future<RpcResult<UpdateFlowOutput>> updateFlow(UpdateFlowInput input) {
+    public ListenableFuture<RpcResult<UpdateFlowOutput>> updateFlow(UpdateFlowInput input) {
         @SuppressWarnings("unchecked")
         org.opendaylight.controller.sal.core.Node node = InventoryMapping.toAdNode((InstanceIdentifier<Node>) input
                 .getNode().getValue());
index 4bc23fe33b0b9a7c1709d5440700f7b56d28c0ed..c5cbecabedae35c96eb1fd0cad2ae5059253d074 100644 (file)
@@ -13,7 +13,6 @@ import java.util.List;
 import java.util.concurrent.Future;
 
 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
-import org.opendaylight.controller.sal.common.util.Futures;
 import org.opendaylight.controller.sal.common.util.Rpcs;
 import org.opendaylight.controller.sal.compatibility.FromSalConversionsUtils;
 import org.opendaylight.controller.sal.compatibility.InventoryMapping;
@@ -64,6 +63,9 @@ import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
 public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService, IReadServiceListener{
 
     private static final Logger LOG = LoggerFactory.getLogger(FlowStatisticsAdapter.class);
@@ -73,7 +75,7 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService,
     @Override
     public Future<RpcResult<GetAggregateFlowStatisticsFromFlowTableForAllFlowsOutput>> getAggregateFlowStatisticsFromFlowTableForAllFlows(
             GetAggregateFlowStatisticsFromFlowTableForAllFlowsInput input) {
-        //TODO: No supported API exist in AD-SAL, it can either be implemented by fetching all the stats of the flows and 
+        //TODO: No supported API exist in AD-SAL, it can either be implemented by fetching all the stats of the flows and
         // generating aggregate flow statistics out of those individual flow stats.
         return null;
     }
@@ -81,13 +83,13 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService,
     @Override
     public Future<RpcResult<GetAggregateFlowStatisticsFromFlowTableForGivenMatchOutput>> getAggregateFlowStatisticsFromFlowTableForGivenMatch(
             GetAggregateFlowStatisticsFromFlowTableForGivenMatchInput input) {
-        //TODO: No supported API exist in AD-SAL, it can either be implemented by fetching all the stats of the flows and 
+        //TODO: No supported API exist in AD-SAL, it can either be implemented by fetching all the stats of the flows and
         // generating aggregate flow statistics out of those individual flow stats.
         return null;
     }
 
     @Override
-    public Future<RpcResult<GetAllFlowStatisticsFromFlowTableOutput>> getAllFlowStatisticsFromFlowTable(
+    public ListenableFuture<RpcResult<GetAllFlowStatisticsFromFlowTableOutput>> getAllFlowStatisticsFromFlowTable(
             GetAllFlowStatisticsFromFlowTableInput input) {
         GetAllFlowStatisticsFromFlowTableOutput rpcResultType = null;
         boolean rpcResultBool = false;
@@ -99,7 +101,7 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService,
             GetAllFlowStatisticsFromFlowTableOutputBuilder builder = new GetAllFlowStatisticsFromFlowTableOutputBuilder();
             builder.setTransactionId(new TransactionId(new BigInteger("0")));
             rpcResultType = builder.setFlowAndStatisticsMapList(flowsStatistics).build();
-            
+
             rpcResultBool = true;
         } catch (ConstructionException e) {
             LOG.error(e.getMessage());
@@ -112,9 +114,9 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService,
      * Essentially this API will return the same result as getAllFlowStatisticsFromFlowTable
      */
     @Override
-    public Future<RpcResult<GetAllFlowsStatisticsFromAllFlowTablesOutput>> getAllFlowsStatisticsFromAllFlowTables(
+    public ListenableFuture<RpcResult<GetAllFlowsStatisticsFromAllFlowTablesOutput>> getAllFlowsStatisticsFromAllFlowTables(
             GetAllFlowsStatisticsFromAllFlowTablesInput input) {
-        
+
         GetAllFlowsStatisticsFromAllFlowTablesOutput rpcResultType = null;
         boolean rpcResultBool = false;
 
@@ -125,7 +127,7 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService,
             GetAllFlowsStatisticsFromAllFlowTablesOutputBuilder builder = new GetAllFlowsStatisticsFromAllFlowTablesOutputBuilder();
             builder.setTransactionId(new TransactionId(new BigInteger("0")));
             rpcResultType = builder.setFlowAndStatisticsMapList(flowsStatistics).build();
-            
+
             rpcResultBool = true;
         } catch (ConstructionException e) {
             LOG.error(e.getMessage());
@@ -135,7 +137,7 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService,
     }
 
     @Override
-    public Future<RpcResult<GetFlowStatisticsFromFlowTableOutput>> getFlowStatisticsFromFlowTable(
+    public ListenableFuture<RpcResult<GetFlowStatisticsFromFlowTableOutput>> getFlowStatisticsFromFlowTable(
             GetFlowStatisticsFromFlowTableInput input) {
         GetFlowStatisticsFromFlowTableOutput rpcResultType = null;
         boolean rpcResultBool = false;
@@ -170,7 +172,7 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService,
     public void nodeConnectorStatisticsUpdated(Node node, List<NodeConnectorStatistics> ncStatsList) {
         NodeConnectorStatisticsUpdateBuilder nodeConnectorStatisticsUpdateBuilder = new NodeConnectorStatisticsUpdateBuilder();
         List<NodeConnectorStatisticsAndPortNumberMap> nodeConnectorStatistics = toOdNodeConnectorStatistics(ncStatsList);
-        
+
         nodeConnectorStatisticsUpdateBuilder.setNodeConnectorStatisticsAndPortNumberMap(nodeConnectorStatistics);
         nodeConnectorStatisticsUpdateBuilder.setMoreReplies(false);
         nodeConnectorStatisticsUpdateBuilder.setTransactionId(null);
@@ -180,9 +182,9 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService,
 
     @Override
     public void nodeTableStatisticsUpdated(Node node, List<NodeTableStatistics> tableStatsList) {
-        
-        FlowTableStatisticsUpdateBuilder flowTableStatisticsUpdateBuilder = new FlowTableStatisticsUpdateBuilder();  
-        
+
+        FlowTableStatisticsUpdateBuilder flowTableStatisticsUpdateBuilder = new FlowTableStatisticsUpdateBuilder();
+
         List<FlowTableAndStatisticsMap>  flowTableStatistics = toOdFlowTableStatistics(tableStatsList);
         flowTableStatisticsUpdateBuilder.setFlowTableAndStatisticsMap(flowTableStatistics);
         flowTableStatisticsUpdateBuilder.setMoreReplies(false);
@@ -194,7 +196,7 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService,
         @Override
     public void descriptionStatisticsUpdated(Node node, NodeDescription nodeDescription) {
             // TODO which *StatisticsUpdated interface should be used?
-        
+
     }
 
     private List<FlowAndStatisticsMapList> toOdFlowsStatistics(List<FlowOnNode> flowsOnNode) {
@@ -234,7 +236,7 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService,
     }
 
     private List<FlowTableAndStatisticsMap> toOdFlowTableStatistics(List<NodeTableStatistics> tableStatsList) {
-        
+
         List<FlowTableAndStatisticsMap> flowTableStatsMap = new ArrayList<FlowTableAndStatisticsMap>();
         for (NodeTableStatistics nodeTableStatistics : tableStatsList) {
             FlowTableAndStatisticsMapBuilder flowTableAndStatisticsMapBuilder = new FlowTableAndStatisticsMapBuilder();
@@ -245,7 +247,7 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService,
             flowTableAndStatisticsMapBuilder.setTableId(new TableId((short)nodeTableStatistics.getNodeTable().getID()));
             flowTableStatsMap.add(flowTableAndStatisticsMapBuilder.build());
         }
-        
+
         return flowTableStatsMap;
     }
 
@@ -254,7 +256,7 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService,
         List<NodeConnectorStatisticsAndPortNumberMap> nodeConnectorStatisticsList = new ArrayList<NodeConnectorStatisticsAndPortNumberMap>();
         for(NodeConnectorStatistics ofNodeConnectorStatistics : ncStatsList){
             NodeConnectorStatisticsAndPortNumberMapBuilder nodeConnectorStatisticsAndPortNumberMapBuilder = new NodeConnectorStatisticsAndPortNumberMapBuilder();
-            
+
             nodeConnectorStatisticsAndPortNumberMapBuilder.setBytes(extractBytes(ofNodeConnectorStatistics));
             nodeConnectorStatisticsAndPortNumberMapBuilder.setCollisionCount(toBI(ofNodeConnectorStatistics.getCollisionCount()));
             nodeConnectorStatisticsAndPortNumberMapBuilder.setDuration(null);
@@ -268,7 +270,7 @@ public class FlowStatisticsAdapter implements OpendaylightFlowStatisticsService,
             nodeConnectorStatisticsAndPortNumberMapBuilder.setTransmitErrors(toBI(ofNodeConnectorStatistics.getTransmitErrorCount()));
             nodeConnectorStatisticsList.add(nodeConnectorStatisticsAndPortNumberMapBuilder.build());
         }
-        
+
         return nodeConnectorStatisticsList;
     }
 
index 5092995eb05cb174121f17799008ce248ee58c33..1ea0a3e132c65bc25d33dd0adfb542502954807a 100644 (file)
@@ -47,7 +47,6 @@
             <plugin>
                 <groupId>org.opendaylight.yangtools</groupId>
                 <artifactId>yang-maven-plugin</artifactId>
-                <version>${yangtools.version}</version>
                 <executions>
                     <execution>
                         <goals>
index f900c0b18c6558e0808c7fca3452bf3608aaeddf..6cc06ba70502b2e4fed1d315120326cd6552315d 100644 (file)
 
         <!-- Dependency Versions -->
         <mockito.version>1.9.5</mockito.version>
-        <xtend.version>2.4.3</xtend.version>
+
 
         <!-- Sonar properties using jacoco to retrieve integration test results -->
         <sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
         <sonar.branch>${user.name}-private-view</sonar.branch>
         <sonar.language>java</sonar.language>
         <exam.version>3.0.0</exam.version>
-        <sal.version>0.7.1-SNAPSHOT</sal.version>
+        <sal.version>0.8.1-SNAPSHOT</sal.version>
     </properties>
 
     <dependencyManagement>
                 <artifactId>slf4j-api</artifactId>
                 <version>${slf4j.version}</version>
             </dependency>
-            <dependency>
-                <groupId>org.eclipse.xtend</groupId>
-                <artifactId>org.eclipse.xtend.lib</artifactId>
-                <version>${xtend.version}</version>
-            </dependency>
+
             <dependency>
                 <groupId>org.osgi</groupId>
                 <artifactId>org.osgi.core</artifactId>
index 2da031e54008cb68c5cf23cddc84b4cd50742da1..e5e314cd877d74ab7e52d505a80cf4e1ea059d44 100644 (file)
@@ -7,25 +7,33 @@
  */
 package org.opendaylight.controller.sal.connector.remoterpc.api;
 
-import java.util.Map;
 import java.util.Set;
 
 public interface RoutingTable<I,R> {
 
-
-
   /**
-   * Adds a network address for the route. If address for route
-   * exists, appends the address to the list
+   * Adds a network address for the route. If the route already exists,
+   * it throws <code>DuplicateRouteException</code>.
+   * This method would be used when registering a global service.
+   *
    *
    * @param routeId route identifier
    * @param route network address
-   * @throws RoutingTableException for any logical exception
+   * @throws DuplicateRouteException
+   * @throws RoutingTableException
+   */
+  public void addGlobalRoute(I routeId, R route) throws  RoutingTableException, SystemException;
+
+  /**
+   * Remove the route.
+   * This method would be used when registering a global service.
+   * @param routeId
+   * @throws RoutingTableException
    * @throws SystemException
    */
-  public void addRoute(I routeId, R route) throws  RoutingTableException,SystemException;
+  public void removeGlobalRoute(I routeId) throws RoutingTableException, SystemException;
 
-    /**
+  /**
    * Adds a network address for the route. If the route already exists,
    * it throws <code>DuplicateRouteException</code>.
    * This method would be used when registering a global service.
@@ -36,9 +44,18 @@ public interface RoutingTable<I,R> {
    * @throws DuplicateRouteException
    * @throws RoutingTableException
    */
-  public void addGlobalRoute(I routeId, R route) throws  RoutingTableException, SystemException;
-
+  public R getGlobalRoute(I routeId) throws  RoutingTableException, SystemException;
 
+  /**
+   * Adds a network address for the route. If address for route
+   * exists, appends the address to the list
+   *
+   * @param routeId route identifier
+   * @param route network address
+   * @throws RoutingTableException for any logical exception
+   * @throws SystemException
+   */
+  public void addRoute(I routeId, R route) throws RoutingTableException,SystemException;
 
 
   /**
@@ -47,17 +64,28 @@ public interface RoutingTable<I,R> {
    * @param routeId
    * @param route
    */
-  public void removeRoute(I routeId, R route);
+  public void removeRoute(I routeId, R route) throws RoutingTableException,SystemException;
 
+  /**
+   * Adds address for a set of route identifiers. If address for route
+   * exists, appends the address to the set.
+   *
+   * @param routeIds a set of routeIds
+   * @param route network address
+   * @throws RoutingTableException for any logical exception
+   * @throws SystemException
+   */
+  public void addRoutes(Set<I> routeIds, R route) throws  RoutingTableException,SystemException;
 
-    /**
-     * Remove the route.
-     * This method would be used when registering a global service.
-     * @param routeId
-     * @throws RoutingTableException
-     * @throws SystemException
-     */
-    public void removeGlobalRoute(I routeId) throws RoutingTableException, SystemException;
+  /**
+   * Removes address for a set of route identifiers.
+   *
+   * @param routeIds a set of routeIds
+   * @param route network address
+   * @throws RoutingTableException for any logical exception
+   * @throws SystemException
+   */
+  public void removeRoutes(Set<I> routeIds, R route) throws  RoutingTableException,SystemException;
 
   /**
    * Returns a set of network addresses associated with this route
@@ -66,29 +94,14 @@ public interface RoutingTable<I,R> {
    */
   public Set<R> getRoutes(I routeId);
 
-  /**
-   * Returns all network addresses stored in the table
-   * @return
-   */
-  public Set<Map.Entry> getAllRoutes();
 
   /**
-   * Returns only one address from the list of network addresses
-   * associated with the route. The algorithm to determine that
-   * one address is upto the implementer
+   * Returns the last inserted address from the list of network addresses
+   * associated with the route.
    * @param routeId
    * @return
    */
-  public R getARoute(I routeId);
-
-    /**
-     *
-     * This will be removed after listeners
-     * have made change on their end to use whiteboard pattern
-     * @deprecated
-     */
-
-  public void registerRouteChangeListener(RouteChangeListener listener);
+  public R getLastAddedRoute(I routeId);
 
   public class DuplicateRouteException extends RoutingTableException {
       public DuplicateRouteException(String message) {
index 6e2d280a89f5158358c3d6757c7c1e4e2f72e64e..a826a3c1d7bfcc3bac9c43cd2ae43345bff1b21d 100644 (file)
@@ -67,7 +67,8 @@ public class Activator extends ComponentActivatorAbstractBase {
         if (imp.equals(RoutingTableImpl.class)) {
             Dictionary<String, Set<String>> props = new Hashtable<String, Set<String>>();
             Set<String> propSet = new HashSet<String>();
-            propSet.add(RoutingTableImpl.ROUTING_TABLE_GLOBAL_CACHE);
+            propSet.add(RoutingTableImpl.GLOBALRPC_CACHE);
+            propSet.add(RoutingTableImpl.RPC_CACHE);
             props.put(CACHE_UPDATE_AWARE_REGISTRY_KEY, propSet);
 
             c.setInterface(new String[] { RoutingTable.class.getName(),ICacheUpdateAware.class.getName()  }, props);
index 40c4c6b43625d9c99eecb786a1556762cbdc0085..d6b42faccf60f8351f849cdd350f02819bec0674 100644 (file)
@@ -8,15 +8,11 @@
 
 package org.opendaylight.controller.sal.connector.remoterpc.impl;
 
+import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableSet;
 import org.apache.felix.dm.Component;
-import org.opendaylight.controller.clustering.services.CacheConfigException;
-import org.opendaylight.controller.clustering.services.CacheExistException;
-import org.opendaylight.controller.clustering.services.CacheListenerAddException;
-import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
-import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
-import org.opendaylight.controller.clustering.services.IClusterServices;
-import org.opendaylight.controller.sal.connector.remoterpc.api.RouteChangeListener;
+import org.opendaylight.controller.clustering.services.*;
 import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
 import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException;
 import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException;
@@ -27,309 +23,415 @@ import javax.transaction.HeuristicMixedException;
 import javax.transaction.HeuristicRollbackException;
 import javax.transaction.NotSupportedException;
 import javax.transaction.RollbackException;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 import java.util.concurrent.ConcurrentMap;
 
-/**
- * @author: syedbahm
- */
 public class RoutingTableImpl<I, R> implements RoutingTable<I, R>, ICacheUpdateAware<I, R> {
-    public static final String ROUTING_TABLE_GLOBAL_CACHE = "routing_table_global_cache";
 
-    private Logger log = LoggerFactory.getLogger(RoutingTableImpl.class);
+  private Logger log = LoggerFactory.getLogger(RoutingTableImpl.class);
 
-    private IClusterGlobalServices clusterGlobalServices = null;
-    private RoutingTableImpl routingTableInstance = null;
-    private ConcurrentMap routingTableCache = null;
-    private Set<RouteChangeListener> routeChangeListeners = Collections
-            .synchronizedSet(new HashSet<RouteChangeListener>());
+  private IClusterGlobalServices clusterGlobalServices = null;
 
-    public RoutingTableImpl() {
-    }
+  private ConcurrentMap<I,R> globalRpcCache = null;
+  private ConcurrentMap<I, LinkedHashSet<R>> rpcCache = null;  //need routes to ordered by insert-order
 
-    @Override
-    public void addRoute(I routeId, R route) throws RoutingTableException {
-        throw new UnsupportedOperationException(" Not implemented yet!");
-    }
+  public static final String GLOBALRPC_CACHE = "remoterpc_routingtable.globalrpc_cache";
+  public static final String RPC_CACHE = "remoterpc_routingtable.rpc_cache";
 
-    @Override
-    public void addGlobalRoute(I routeId, R route) throws RoutingTableException, SystemException {
-        Preconditions.checkNotNull(routeId, "addGlobalRoute: routeId cannot be null!");
-        Preconditions.checkNotNull(route, "addGlobalRoute: route cannot be null!");
-        try {
-
-            Set<R> existingRoute = null;
-            // ok does the global route is already registered ?
-            if ((existingRoute = getRoutes(routeId)) == null) {
-
-                if (log.isDebugEnabled()) {
-                    log.debug("addGlobalRoute: adding  a new route with id" + routeId + " and value = "
-                            + route);
-                }
-                // lets start a transaction
-                clusterGlobalServices.tbegin();
-
-                routingTableCache.put(routeId, route);
-                clusterGlobalServices.tcommit();
-            } else {
-                throw new DuplicateRouteException(" There is already existing route " + existingRoute);
-            }
-
-        } catch (NotSupportedException|HeuristicRollbackException|RollbackException|HeuristicMixedException e) {
-            throw new RoutingTableException("Transaction error - while trying to create route id="
-                    + routeId + "with route" + route, e);
-        } catch (javax.transaction.SystemException e) {
-            throw new SystemException("System error occurred - while trying to create with value", e);
-        }
+  public RoutingTableImpl() {
+  }
 
-    }
+  @Override
+  public R getGlobalRoute(I routeId) throws RoutingTableException, SystemException {
+    Preconditions.checkNotNull(routeId, "getGlobalRoute: routeId cannot be null!");
+    return globalRpcCache.get(routeId);
+  }
 
-    @Override
-    public void removeRoute(I routeId, R route) {
-        throw new UnsupportedOperationException("Not implemented yet!");
+  @Override
+  public void addGlobalRoute(I routeId, R route) throws RoutingTableException, SystemException {
+    Preconditions.checkNotNull(routeId, "addGlobalRoute: routeId cannot be null!");
+    Preconditions.checkNotNull(route, "addGlobalRoute: route cannot be null!");
+    try {
+
+      log.debug("addGlobalRoute: adding  a new route with id[{}] and value [{}]", routeId, route);
+      clusterGlobalServices.tbegin();
+      if (globalRpcCache.putIfAbsent(routeId, route) != null) {
+        throw new DuplicateRouteException(" There is already existing route " + routeId);
+      }
+      clusterGlobalServices.tcommit();
+
+    } catch (NotSupportedException | HeuristicRollbackException | RollbackException | HeuristicMixedException e) {
+      throw new RoutingTableException("Transaction error - while trying to create route id="
+          + routeId + "with route" + route, e);
+    } catch (javax.transaction.SystemException e) {
+      throw new SystemException("System error occurred - while trying to create with value", e);
     }
 
-    @Override
-    public void removeGlobalRoute(I routeId) throws RoutingTableException, SystemException {
-        Preconditions.checkNotNull(routeId, "removeGlobalRoute: routeId cannot be null!");
-        try {
-            if (log.isDebugEnabled()) {
-                log.debug("removeGlobalRoute: removing  a new route with id" + routeId);
-            }
-            // lets start a transaction
-            clusterGlobalServices.tbegin();
-
-            routingTableCache.remove(routeId);
-            clusterGlobalServices.tcommit();
-
-        } catch (NotSupportedException|HeuristicRollbackException|RollbackException|HeuristicMixedException e) {
-            throw new RoutingTableException("Transaction error - while trying to remove route id="
-                    + routeId, e);
-        } catch (javax.transaction.SystemException e) {
-            throw new SystemException("System error occurred - while trying to remove with value", e);
-        }
+  }
+
+  @Override
+  public void removeGlobalRoute(I routeId) throws RoutingTableException, SystemException {
+    Preconditions.checkNotNull(routeId, "removeGlobalRoute: routeId cannot be null!");
+    try {
+      log.debug("removeGlobalRoute: removing  a new route with id [{}]", routeId);
+
+      clusterGlobalServices.tbegin();
+      globalRpcCache.remove(routeId);
+      clusterGlobalServices.tcommit();
+
+    } catch (NotSupportedException | HeuristicRollbackException | RollbackException | HeuristicMixedException e) {
+      throw new RoutingTableException("Transaction error - while trying to remove route id="
+          + routeId, e);
+    } catch (javax.transaction.SystemException e) {
+      throw new SystemException("System error occurred - while trying to remove with value", e);
     }
+  }
+
 
-    @Override
-    public Set<R> getRoutes(I routeId) {
+  @Override
+  public Set<R> getRoutes(I routeId) {
+    Preconditions.checkNotNull(routeId, "getRoutes: routeId cannot be null!");
+    Set<R> routes = rpcCache.get(routeId);
 
-        // Note: currently works for global routes only wherein there is just single
-        // route
-        Preconditions.checkNotNull(routeId, "getARoute: routeId cannot be null!");
-        R route = (R)routingTableCache.get(routeId);
-        Set<R>routes = null;
-        if(route !=null){
-           routes = new HashSet<R>();
-           routes.add(route);
-        }
+    if (routes == null) return Collections.emptySet();
+
+    return ImmutableSet.copyOf(routes);
+  }
 
-        return routes;
-    }
+
+
+  public R getLastAddedRoute(I routeId) {
+
+    Set<R> routes = getRoutes(routeId);
+
+    if (routes.isEmpty()) return null;
+
+    R route = null;
+    Iterator<R> iter = routes.iterator();
+    while (iter.hasNext())
+      route = iter.next();
+
+    return route;
+  }
 
   @Override
-  public Set<Map.Entry> getAllRoutes() {
-    return routingTableCache.entrySet();
+  public void addRoute(I routeId, R route)  throws RoutingTableException, SystemException {
+    Preconditions.checkNotNull(routeId, "addRoute: routeId cannot be null");
+    Preconditions.checkNotNull(route, "addRoute: route cannot be null");
+
+    try{
+      clusterGlobalServices.tbegin();
+      log.debug("addRoute: adding a route with k/v [{}/{}]", routeId, route);
+      threadSafeAdd(routeId, route);
+      clusterGlobalServices.tcommit();
+
+    } catch (NotSupportedException | HeuristicRollbackException | RollbackException | HeuristicMixedException e) {
+      throw new RoutingTableException("Transaction error - while trying to remove route id="
+          + routeId, e);
+    } catch (javax.transaction.SystemException e) {
+      throw new SystemException("System error occurred - while trying to remove with value", e);
+    }
   }
 
   @Override
-    public R getARoute(I routeId) {
-        throw new UnsupportedOperationException("Not implemented yet!");
+  public void addRoutes(Set<I> routeIds, R route) throws RoutingTableException, SystemException {
+    Preconditions.checkNotNull(routeIds, "addRoutes: routeIds must not be null");
+    for (I routeId : routeIds){
+      addRoute(routeId, route);
     }
+  }
 
-    /**
-     * @deprecated doesn't do anything will be removed once listeners used
-     *             whiteboard pattern Registers listener for sending any change
-     *             notification
-     * @param listener
-     */
-    @Override
-    public void registerRouteChangeListener(RouteChangeListener listener) {
+  @Override
+  public void removeRoute(I routeId, R route) throws RoutingTableException, SystemException {
+    Preconditions.checkNotNull(routeId, "removeRoute: routeId cannot be null!");
+    Preconditions.checkNotNull(route, "removeRoute: route cannot be null!");
 
-    }
+    LinkedHashSet<R> routes = rpcCache.get(routeId);
+    if (routes == null) return;
 
-    public void setRouteChangeListener(RouteChangeListener rcl) {
-        if(rcl != null){
-            routeChangeListeners.add(rcl);
-        }else{
-            log.warn("setRouteChangeListener called with null listener");
-        }
-    }
+    try {
+      log.debug("removeRoute: removing  a new route with k/v [{}/{}]", routeId, route);
 
-    public void unSetRouteChangeListener(RouteChangeListener rcl) {
-        if(rcl != null){
-         routeChangeListeners.remove(rcl);
-        }else{
-            log.warn("unSetRouteChangeListener called with null listener");
-        }
+      clusterGlobalServices.tbegin();
+      threadSafeRemove(routeId, route);
+      clusterGlobalServices.tcommit();
+
+    } catch (NotSupportedException | HeuristicRollbackException | RollbackException | HeuristicMixedException e) {
+      throw new RoutingTableException("Transaction error - while trying to remove route id="
+          + routeId, e);
+    } catch (javax.transaction.SystemException e) {
+      throw new SystemException("System error occurred - while trying to remove with value", e);
     }
+  }
 
-    /**
-     * Returning the set of route change listeners for Unit testing Note: the
-     * package scope is default
-     *
-     * @return List of registered RouteChangeListener<I,R> listeners
-     */
-    Set<RouteChangeListener> getRegisteredRouteChangeListeners() {
-        return routeChangeListeners;
+  @Override
+  public void removeRoutes(Set<I> routeIds, R route) throws RoutingTableException, SystemException {
+    Preconditions.checkNotNull(routeIds, "removeRoutes: routeIds must not be null");
+    for (I routeId : routeIds){
+      removeRoute(routeId, route);
     }
+  }
 
-    public void setClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) {
-        this.clusterGlobalServices = clusterGlobalServices;
+  /**
+   * This method guarantees that no 2 thread over write each other's changes.
+   * Just so that we dont end up in infinite loop, it tries for 100 times then throw
+   */
+  private void threadSafeAdd(I routeId, R route) {
+
+    for (int i=0;i<100;i++){
+
+      LinkedHashSet<R> updatedRoutes = new LinkedHashSet<>();
+      updatedRoutes.add(route);
+      LinkedHashSet<R> oldRoutes = rpcCache.putIfAbsent(routeId, updatedRoutes);
+      if (oldRoutes == null) return;
+
+      updatedRoutes = new LinkedHashSet<>(oldRoutes);
+      updatedRoutes.add(route);
+
+      if (rpcCache.replace(routeId, oldRoutes, updatedRoutes)) return;
     }
+    //the method did not already return means it failed to add route in 10 attempts
+    throw new IllegalStateException("Failed to add route [" + routeId + "]");
+  }
+
+  /**
+   * This method guarantees that no 2 thread over write each other's changes.
+   * Just so that we dont end up in infinite loop, it tries for 10 times then throw
+   */
+  private void threadSafeRemove(I routeId, R route) {
+    LinkedHashSet<R> updatedRoutes = null;
+    for (int i=0;i<10;i++){
+      LinkedHashSet<R> oldRoutes = rpcCache.get(routeId);
+
+      // if route to be deleted is the only entry in the set then remove routeId from the cache
+      if ((oldRoutes.size() == 1) && oldRoutes.contains(route)){
+        rpcCache.remove(routeId);
+        return;
+      }
+
+      // if there are multiple routes for this routeId, remove the route to be deleted only from the set.
+      updatedRoutes = new LinkedHashSet<>(oldRoutes);
+      updatedRoutes.remove(route);
+      if (rpcCache.replace(routeId, oldRoutes, updatedRoutes)) return;
 
-    public void unsetClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) {
-        if((clusterGlobalServices != null ) &&  (this.clusterGlobalServices.equals(clusterGlobalServices))){
-            this.clusterGlobalServices = null;
-        }
     }
+    //the method did not already return means it failed to remove route in 10 attempts
+    throw new IllegalStateException("Failed to remove route [" + routeId + "]");
+  }
+
 
-    /**
-     * Creates the Routing Table clustered global services cache
-     *
-     * @throws CacheExistException
-     *           -- cluster global services exception when cache exist
-     * @throws CacheConfigException
-     *           -- cluster global services exception during cache config
-     * @throws CacheListenerAddException
-     *           -- cluster global services exception during adding of listener
-     */
-
-    void createRoutingTableCache() throws CacheExistException, CacheConfigException,
-            CacheListenerAddException {
-        // TBD: HOW DO WE DECIDE ON PROPERTIES OF THE CACHE i.e. what duration it
-        // should be caching?
-
-        // let us check here if the cache already exists -- if so don't create
-        if (!clusterGlobalServices.existCache(ROUTING_TABLE_GLOBAL_CACHE)) {
-
-            if (log.isDebugEnabled()) {
-                log.debug("createRoutingTableCache: creating a new routing table cache "
-                        + ROUTING_TABLE_GLOBAL_CACHE);
-            }
-            routingTableCache = clusterGlobalServices.createCache(ROUTING_TABLE_GLOBAL_CACHE,
-                    EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
-        } else {
-            if (log.isDebugEnabled()) {
-                log.debug("createRoutingTableCache: found existing routing table cache "
-                        + ROUTING_TABLE_GLOBAL_CACHE);
-            }
-            routingTableCache = clusterGlobalServices.getCache(ROUTING_TABLE_GLOBAL_CACHE);
-        }
+//    /**
+//     * @deprecated doesn't do anything will be removed once listeners used
+//     *             whiteboard pattern Registers listener for sending any change
+//     *             notification
+//     * @param listener
+//     */
+//    @Override
+//    public void registerRouteChangeListener(RouteChangeListener listener) {
+//
+//    }
+
+//    public void setRouteChangeListener(RouteChangeListener rcl) {
+//        if(rcl != null){
+//            routeChangeListeners.add(rcl);
+//        }else{
+//            log.warn("setRouteChangeListener called with null listener");
+//        }
+//    }
+//
+//    public void unSetRouteChangeListener(RouteChangeListener rcl) {
+//        if(rcl != null){
+//         routeChangeListeners.remove(rcl);
+//        }else{
+//            log.warn("unSetRouteChangeListener called with null listener");
+//        }
+//    }
+
+  /**
+   * Returning the set of route change listeners for Unit testing Note: the
+   * package scope is default
+   *
+   * @return List of registered RouteChangeListener<I,R> listeners
+   */
+//    Set<RouteChangeListener> getRegisteredRouteChangeListeners() {
+//        return routeChangeListeners;
+//    }
+  public void setClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) {
+    this.clusterGlobalServices = clusterGlobalServices;
+  }
+
+  public void unsetClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) {
+    if ((clusterGlobalServices != null) && (this.clusterGlobalServices.equals(clusterGlobalServices))) {
+      this.clusterGlobalServices = null;
+    }
+  }
 
+  /**
+   * Finds OR Creates clustered cache for Global RPCs
+   *
+   * @throws CacheExistException       -- cluster global services exception when cache exist
+   * @throws CacheConfigException      -- cluster global services exception during cache config
+   * @throws CacheListenerAddException -- cluster global services exception during adding of listener
+   */
+
+  void findOrCreateGlobalRpcCache() throws CacheExistException, CacheConfigException,
+      CacheListenerAddException {
+    // TBD: HOW DO WE DECIDE ON PROPERTIES OF THE CACHE i.e. what duration it
+    // should be caching?
+
+    // let us check here if the cache already exists -- if so don't create
+    if (!clusterGlobalServices.existCache(GLOBALRPC_CACHE)) {
+
+      globalRpcCache = (ConcurrentMap<I,R>) clusterGlobalServices.createCache(GLOBALRPC_CACHE,
+          EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
+      log.debug("Cache created [{}] ", GLOBALRPC_CACHE);
+
+    } else {
+      globalRpcCache = (ConcurrentMap<I,R>) clusterGlobalServices.getCache(GLOBALRPC_CACHE);
+      log.debug("Cache exists [{}] ", GLOBALRPC_CACHE);
     }
+  }
 
-    /**
-     * Function called by the dependency manager when all the required
-     * dependencies are satisfied
-     *
-     */
-    void init(Component c) {
-        try {
-
-            createRoutingTableCache();
-        } catch (CacheExistException e) {
-            throw new IllegalStateException("could not construct routing table cache");
-        } catch (CacheConfigException e) {
-            throw new IllegalStateException("could not construct routing table cache");
-        } catch (CacheListenerAddException e) {
-            throw new IllegalStateException("could not construct routing table cache");
-        }
+  /**
+   * Finds OR Creates clustered cache for Routed RPCs
+   *
+   * @throws CacheExistException       -- cluster global services exception when cache exist
+   * @throws CacheConfigException      -- cluster global services exception during cache config
+   * @throws CacheListenerAddException -- cluster global services exception during adding of listener
+   */
+
+  void findOrCreateRpcCache() throws CacheExistException, CacheConfigException,
+      CacheListenerAddException {
+    // TBD: HOW DO WE DECIDE ON PROPERTIES OF THE CACHE i.e. what duration it
+    // should be caching?
+
+    if (clusterGlobalServices.existCache(RPC_CACHE)){
+      rpcCache = (ConcurrentMap<I,LinkedHashSet<R>>) clusterGlobalServices.getCache(RPC_CACHE);
+      log.debug("Cache exists [{}] ", RPC_CACHE);
+      return;
     }
 
-    /**
-     * Get routing table method is useful for unit testing <note>It has package
-     * scope</note>
-     */
-    ConcurrentMap getRoutingTableCache() {
-        return this.routingTableCache;
+    //cache doesnt exist, create one
+    rpcCache = (ConcurrentMap<I,LinkedHashSet<R>>) clusterGlobalServices.createCache(RPC_CACHE,
+          EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
+    log.debug("Cache created [{}] ", RPC_CACHE);
+  }
+
+
+  /**
+   * Function called by the dependency manager when all the required
+   * dependencies are satisfied
+   */
+  void init(Component c) {
+    try {
+
+      findOrCreateGlobalRpcCache();
+      findOrCreateRpcCache();
+
+    } catch (CacheExistException|CacheConfigException|CacheListenerAddException e) {
+      throw new IllegalStateException("could not construct routing table cache");
     }
+  }
+
+  /**
+   * Useful for unit testing <note>It has package
+   * scope</note>
+   */
+  ConcurrentMap getGlobalRpcCache() {
+    return this.globalRpcCache;
+  }
+
+  /**
+   * Useful for unit testing <note>It has package
+   * scope</note>
+   */
+  ConcurrentMap getRpcCache() {
+    return this.rpcCache;
+  }
 
-    /**
-     * This is used from integration test NP rest API to check out the result of the
-     * cache population
-     * <Note> For testing purpose only-- use it wisely</Note>
-     * @return
-     */
-    public String dumpRoutingTableCache(){
-       Set<Map.Entry<I, R>> cacheEntrySet = this.routingTableCache.entrySet();
-       StringBuilder sb = new StringBuilder();
-       for(Map.Entry<I,R> entry:cacheEntrySet){
-           sb.append("Key:").append(entry.getKey()).append("---->Value:")
-                   .append((entry.getValue() != null)?entry.getValue():"null")
-                   .append("\n");
-       }
-       return sb.toString();
+  /**
+   * This is used from integration test NP rest API to check out the result of the
+   * cache population
+   * <Note> For testing purpose only-- use it wisely</Note>
+   *
+   * @return
+   */
+  public String dumpGlobalRpcCache() {
+    Set<Map.Entry<I, R>> cacheEntrySet = this.globalRpcCache.entrySet();
+    StringBuilder sb = new StringBuilder();
+    for (Map.Entry<I, R> entry : cacheEntrySet) {
+      sb.append("Key:").append(entry.getKey()).append("---->Value:")
+          .append((entry.getValue() != null) ? entry.getValue() : "null")
+          .append("\n");
     }
+    return sb.toString();
+  }
 
-    /**
-     * Invoked when a new entry is available in the cache, the key is only
-     * provided, the value will come as an entryUpdate invocation
-     *
-     * @param key
-     *          Key for the entry just created
-     * @param cacheName
-     *          name of the cache for which update has been received
-     * @param originLocal
-     *          true if the event is generated from this node
-     */
-    @Override
-    public void entryCreated(I key, String cacheName, boolean originLocal) {
-        // TBD: do we require this.
-        if (log.isDebugEnabled()) {
-            log.debug("RoutingTableUpdates: entryCreated  routeId = " + key + " cacheName=" + cacheName);
-        }
+  public String dumpRpcCache() {
+    Set<Map.Entry<I, LinkedHashSet<R>>> cacheEntrySet = this.rpcCache.entrySet();
+    StringBuilder sb = new StringBuilder();
+    for (Map.Entry<I, LinkedHashSet<R>> entry : cacheEntrySet) {
+      sb.append("Key:").append(entry.getKey()).append("---->Value:")
+          .append((entry.getValue() != null) ? entry.getValue() : "null")
+          .append("\n");
     }
+    return sb.toString();
+  }
+  /**
+   * Invoked when a new entry is available in the cache, the key is only
+   * provided, the value will come as an entryUpdate invocation
+   *
+   * @param key         Key for the entry just created
+   * @param cacheName   name of the cache for which update has been received
+   * @param originLocal true if the event is generated from this node
+   */
+  @Override
+  public void entryCreated(I key, String cacheName, boolean originLocal) {
+    // TBD: do we require this.
+    if (log.isDebugEnabled()) {
+      log.debug("RoutingTableUpdates: entryCreated  routeId = " + key + " cacheName=" + cacheName);
+    }
+  }
 
-    /**
-     * Called anytime a given entry is updated
-     *
-     * @param key
-     *          Key for the entry modified
-     * @param new_value
-     *          the new value the key will have
-     * @param cacheName
-     *          name of the cache for which update has been received
-     * @param originLocal
-     *          true if the event is generated from this node
-     */
-    @Override
-    public void entryUpdated(I key, R new_value, String cacheName, boolean originLocal) {
-        if (log.isDebugEnabled()) {
-            log.debug("RoutingTableUpdates: entryUpdated  routeId = " + key + ",value = " + new_value
-                    + " ,cacheName=" + cacheName + " originLocal="+originLocal);
-        }
-        if (!originLocal) {
-            for (RouteChangeListener rcl : routeChangeListeners) {
-                rcl.onRouteUpdated(key, new_value);
-            }
-        }
+  /**
+   * Called anytime a given entry is updated
+   *
+   * @param key         Key for the entry modified
+   * @param new_value   the new value the key will have
+   * @param cacheName   name of the cache for which update has been received
+   * @param originLocal true if the event is generated from this node
+   */
+  @Override
+  public void entryUpdated(I key, R new_value, String cacheName, boolean originLocal) {
+    if (log.isDebugEnabled()) {
+      log.debug("RoutingTableUpdates: entryUpdated  routeId = " + key + ",value = " + new_value
+          + " ,cacheName=" + cacheName + " originLocal=" + originLocal);
     }
+//        if (!originLocal) {
+//            for (RouteChangeListener rcl : routeChangeListeners) {
+//                rcl.onRouteUpdated(key, new_value);
+//            }
+//        }
+  }
 
-    /**
-     * Called anytime a given key is removed from the ConcurrentHashMap we are
-     * listening to.
-     *
-     * @param key
-     *          Key of the entry removed
-     * @param cacheName
-     *          name of the cache for which update has been received
-     * @param originLocal
-     *          true if the event is generated from this node
-     */
-    @Override
-    public void entryDeleted(I key, String cacheName, boolean originLocal) {
-        if (log.isDebugEnabled()) {
-            log.debug("RoutingTableUpdates: entryUpdated  routeId = " + key + " local = " + originLocal
-                    + " cacheName=" + cacheName + " originLocal="+originLocal);
-        }
-        if (!originLocal) {
-            for (RouteChangeListener rcl : routeChangeListeners) {
-                rcl.onRouteDeleted(key);
-            }
-        }
+  /**
+   * Called anytime a given key is removed from the ConcurrentHashMap we are
+   * listening to.
+   *
+   * @param key         Key of the entry removed
+   * @param cacheName   name of the cache for which update has been received
+   * @param originLocal true if the event is generated from this node
+   */
+  @Override
+  public void entryDeleted(I key, String cacheName, boolean originLocal) {
+    if (log.isDebugEnabled()) {
+      log.debug("RoutingTableUpdates: entryUpdated  routeId = " + key + " local = " + originLocal
+          + " cacheName=" + cacheName + " originLocal=" + originLocal);
     }
+//        if (!originLocal) {
+//            for (RouteChangeListener rcl : routeChangeListeners) {
+//                rcl.onRouteDeleted(key);
+//            }
+//        }
+  }
 }
\ No newline at end of file
index 50460d4e5ec897892a9a507a1b48244098887c86..0987df595689176b2d734da6c048ef00a909b2b0 100644 (file)
@@ -10,196 +10,321 @@ package org.opendaylight.controller.sal.connector.remoterpc.impl;
 
 import junit.framework.Assert;
 import org.apache.felix.dm.Component;
+import org.junit.After;
+import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
 import org.opendaylight.controller.clustering.services.IClusterServices;
 import org.opendaylight.controller.sal.connector.api.RpcRouter;
-import org.opendaylight.controller.sal.connector.remoterpc.api.RouteChangeListener;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException;
+import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 
 import java.net.URI;
 import java.util.EnumSet;
 import java.util.HashSet;
-import java.util.Iterator;
+import java.util.LinkedHashSet;
 import java.util.Set;
-import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.*;
 
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
 
-/**
- * @author: syedbahm
- */
 public class RoutingTableImplTest {
 
-    private IClusterGlobalServices ics =  mock(IClusterGlobalServices.class);
-    private RoutingTableImpl rti = new RoutingTableImpl();
+  private final URI namespace = URI.create("http://cisco.com/example");
+  private final QName QNAME = new QName(namespace, "global");
 
-    private final URI namespace = URI.create("http://cisco.com/example");
-    private final QName QNAME = new QName(namespace,"global");
+  private IClusterGlobalServices clusterService;
+  private RoutingTableImpl<RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier>, String> routingTable;
+  ConcurrentMap mockGlobalRpcCache;
+  ConcurrentMap mockRpcCache;
 
-    ConcurrentMap concurrentMapMock = mock(ConcurrentMap.class);
+  @Before
+  public void setUp() throws Exception{
+    clusterService = mock(IClusterGlobalServices.class);
+    routingTable = new RoutingTableImpl<RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier>, String>();
+    mockGlobalRpcCache = new ConcurrentHashMap<>();
+    mockRpcCache = new ConcurrentHashMap<>();
+    createRoutingTableCache();
+  }
 
+  @After
+  public void tearDown(){
+    reset(clusterService);
+    mockGlobalRpcCache = null;
+    mockRpcCache = null;
+  }
 
-    @Test
-    public void testAddGlobalRoute() throws Exception {
-        ConcurrentMap concurrentMap = createRoutingTableCache();
+  @Test
+  public void addGlobalRoute_ValidArguments_ShouldAdd() throws Exception {
 
-        Assert.assertNotNull(concurrentMap);
-        RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier =  mock(RpcRouter.RouteIdentifier.class);
-        InstanceIdentifier identifier = mock(InstanceIdentifier.class);
-        when(routeIdentifier.getType()).thenReturn(QNAME);
-        when(routeIdentifier.getRoute()).thenReturn(identifier);
+    Assert.assertNotNull(mockGlobalRpcCache);
+    RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier = getRouteIdentifier();
 
-        rti.addGlobalRoute(routeIdentifier, "172.27.12.1:5000");
+    final String expectedRoute = "172.27.12.1:5000";
+    routingTable.addGlobalRoute(routeIdentifier, expectedRoute);
 
-        Set<String> globalService = new HashSet<String>();
-        globalService.add("172.27.12.1:5000");
+    ConcurrentMap latestCache = routingTable.getGlobalRpcCache();
+    Assert.assertEquals(mockGlobalRpcCache, latestCache);
+    Assert.assertEquals(expectedRoute, latestCache.get(routeIdentifier));
+  }
 
-        when(concurrentMap.get(routeIdentifier)).thenReturn(globalService);
-        ConcurrentMap latestCache = rti.getRoutingTableCache();
+  @Test (expected = RoutingTable.DuplicateRouteException.class)
+  public void addGlobalRoute_DuplicateRoute_ShouldThrow() throws Exception{
 
-        Assert.assertEquals(concurrentMap,latestCache);
+    Assert.assertNotNull(mockGlobalRpcCache);
 
-        Set<String> servicesGlobal = (Set<String>)latestCache.get(routeIdentifier);
-        Assert.assertEquals(servicesGlobal.size(),1);
+    RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier = getRouteIdentifier();
+    routingTable.addGlobalRoute(routeIdentifier, new String());
+    routingTable.addGlobalRoute(routeIdentifier, new String());
+  }
 
-        Assert.assertEquals(servicesGlobal.iterator().next(),"172.27.12.1:5000");
+  @Test
+  public void getGlobalRoute_ExistingRouteId_ShouldReturnRoute() throws Exception {
 
-    }
+    Assert.assertNotNull(mockGlobalRpcCache);
+    RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier = getRouteIdentifier();
+    String expectedRoute = "172.27.12.1:5000";
 
-    @Test
-    public void testGetRoutes() throws Exception {
-        ConcurrentMap concurrentMap = createRoutingTableCache();
+    routingTable.addGlobalRoute(routeIdentifier, expectedRoute);
 
-        Assert.assertNotNull(concurrentMap);
-        RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier =  mock(RpcRouter.RouteIdentifier.class);
-        InstanceIdentifier identifier = mock(InstanceIdentifier.class);
-        when(routeIdentifier.getContext()).thenReturn(QNAME);
-        when(routeIdentifier.getRoute()).thenReturn(identifier);
+    String actualRoute = (String) routingTable.getGlobalRoute(routeIdentifier);
+    Assert.assertEquals(expectedRoute, actualRoute);
+  }
 
-        rti.addGlobalRoute(routeIdentifier, "172.27.12.1:5000");
+  @Test
+  public void getGlobalRoute_NonExistentRouteId_ShouldReturnNull() throws Exception {
 
-        String globalService =   "172.27.12.1:5000";
+    Assert.assertNotNull(mockGlobalRpcCache);
+    RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier = getRouteIdentifier();
 
-        when(concurrentMap.get(routeIdentifier)).thenReturn(globalService);
-        ConcurrentMap latestCache = rti.getRoutingTableCache();
+    String actualRoute = (String) routingTable.getGlobalRoute(routeIdentifier);
+    Assert.assertNull(actualRoute);
+  }
 
-        Assert.assertEquals(concurrentMap,latestCache);
+  @Test
+  public void removeGlobalRoute_ExistingRouteId_ShouldRemove() throws Exception {
 
-        Set<String> servicesGlobal =  rti.getRoutes(routeIdentifier);
+    Assert.assertNotNull(mockGlobalRpcCache);
+    RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier = getRouteIdentifier();
 
+    ConcurrentMap cache = routingTable.getGlobalRpcCache();
+    Assert.assertTrue(cache.size() == 0);
+    routingTable.addGlobalRoute(routeIdentifier, "172.27.12.1:5000");
+    Assert.assertTrue(cache.size() == 1);
 
-        Assert.assertEquals(servicesGlobal.size(),1);
-        Iterator<String> iterator = servicesGlobal.iterator();
-        while(iterator.hasNext()){
-        Assert.assertEquals(iterator.next(),"172.27.12.1:5000");
-        }
+    routingTable.removeGlobalRoute(routeIdentifier);
+    Assert.assertTrue(cache.size() == 0);
 
+  }
 
-    }
-    @Test
-    public void testRegisterRouteChangeListener() throws Exception {
-        Assert.assertEquals(rti.getRegisteredRouteChangeListeners().size(),0);
-        rti.registerRouteChangeListener(new RouteChangeListenerImpl());
+  @Test
+  public void removeGlobalRoute_NonExistentRouteId_ShouldDoNothing() throws Exception {
 
-        Assert.assertEquals(rti.getRegisteredRouteChangeListeners().size(),0); //old should not work
-        //what about the new approach - using whiteboard pattern
-        rti.setRouteChangeListener(new RouteChangeListenerImpl());
+    Assert.assertNotNull(mockGlobalRpcCache);
+    RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier = getRouteIdentifier();
 
-        Assert.assertEquals(rti.getRegisteredRouteChangeListeners().size(),1); //should not work
+    ConcurrentMap cache = routingTable.getGlobalRpcCache();
+    Assert.assertTrue(cache.size() == 0);
 
+    routingTable.removeGlobalRoute(routeIdentifier);
+    Assert.assertTrue(cache.size() == 0);
 
-    }
-    @Test
-    public void testRemoveGlobalRoute()throws Exception {
+  }
 
-        ConcurrentMap concurrentMap = createRoutingTableCache();
+  @Test
+  public void addRoute_ForNewRouteId_ShouldAddRoute() throws Exception {
+    Assert.assertTrue(mockRpcCache.size() == 0);
 
-        Assert.assertNotNull(concurrentMap);
-        RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier =  mock(RpcRouter.RouteIdentifier.class);
-        InstanceIdentifier identifier = mock(InstanceIdentifier.class);
-        when(routeIdentifier.getContext()).thenReturn(QNAME);
-        when(routeIdentifier.getRoute()).thenReturn(identifier);
+    RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeId = getRouteIdentifier();
 
-        rti.addGlobalRoute(routeIdentifier, "172.27.12.1:5000");
+    routingTable.addRoute(routeId, new String());
+    Assert.assertTrue(mockRpcCache.size() == 1);
 
-        String globalService =   "172.27.12.1:5000";
+    Set<String> routes = routingTable.getRoutes(routeId);
+    Assert.assertEquals(1, routes.size());
+  }
 
-        when(concurrentMap.get(routeIdentifier)).thenReturn(globalService);
-        ConcurrentMap latestCache = rti.getRoutingTableCache();
+  @Test
+  public void addRoute_ForExistingRouteId_ShouldAppendRoute() throws Exception {
 
-        Assert.assertEquals(concurrentMap,latestCache);
+    Assert.assertTrue(mockRpcCache.size() == 0);
 
-        Set<String> servicesGlobal =  rti.getRoutes(routeIdentifier);
+    RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeId = getRouteIdentifier();
 
+    String route_1 = "10.0.0.1:5955";
+    String route_2 = "10.0.0.2:5955";
 
-        Assert.assertEquals(servicesGlobal.size(),1);
+    routingTable.addRoute(routeId, route_1);
+    routingTable.addRoute(routeId, route_2);
 
-        Assert.assertEquals(servicesGlobal.iterator().next(),"172.27.12.1:5000");
+    Assert.assertTrue(mockRpcCache.size() == 1);
 
-        rti.removeGlobalRoute(routeIdentifier);
+    Set<String> routes = routingTable.getRoutes(routeId);
+    Assert.assertEquals(2, routes.size());
+    Assert.assertTrue(routes.contains(route_1));
+    Assert.assertTrue(routes.contains(route_2));
+  }
 
-        Assert.assertNotNull(rti.getRoutes(routeIdentifier));
+  @Test
+  public void addRoute_UsingMultipleThreads_ShouldNotOverwrite(){
+    ExecutorService threadPool = Executors.newCachedThreadPool();
 
+    int numOfRoutesToAdd = 100;
+    String routePrefix_1   = "10.0.0.1:555";
+    RpcRouter.RouteIdentifier routeId = getRouteIdentifier();
+    threadPool.submit(addRoutes(numOfRoutesToAdd, routePrefix_1, routeId));
+    String routePrefix_2   = "10.0.0.1:556";
+    threadPool.submit(addRoutes(numOfRoutesToAdd, routePrefix_2, routeId));
 
+    // wait for all tasks to complete; timeout in 10 sec
+    threadPool.shutdown();
+    try {
+      threadPool.awaitTermination(10, TimeUnit.SECONDS); //
+    } catch (InterruptedException e) {
+      e.printStackTrace();
     }
 
-    private ConcurrentMap createRoutingTableCache() throws Exception {
+    Assert.assertEquals(2*numOfRoutesToAdd, routingTable.getRoutes(routeId).size());
+  }
 
-        //here init
-        Component c = mock(Component.class);
+  @Test(expected = NullPointerException.class)
+  public void addRoute_NullRouteId_shouldThrowNpe() throws Exception {
 
-        when(ics.existCache(
-                RoutingTableImpl.ROUTING_TABLE_GLOBAL_CACHE)).thenReturn(false);
+    routingTable.addRoute(null, new String());
+  }
 
-        when(ics.createCache(RoutingTableImpl.ROUTING_TABLE_GLOBAL_CACHE, EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).thenReturn(concurrentMapMock);
-         rti.setClusterGlobalServices(this.ics);
-        rti.init(c);
+  @Test(expected = NullPointerException.class)
+  public void addRoute_NullRoute_shouldThrowNpe() throws Exception{
 
-        Assert.assertEquals(concurrentMapMock,rti.getRoutingTableCache() );
-        return concurrentMapMock;
+    routingTable.addRoute(getRouteIdentifier(), null);
+  }
 
-    }
+  @Test (expected = UnsupportedOperationException.class)
+  public void getRoutes_Call_ShouldReturnImmutableCopy() throws Exception{
+    Assert.assertNotNull(routingTable);
+    RpcRouter.RouteIdentifier routeId = getRouteIdentifier();
+    routingTable.addRoute(routeId, new String());
 
+    Set<String> routes = routingTable.getRoutes(routeId); //returns Immutable Set
 
-    @Test
-    public void testCreateRoutingTableCacheReturnExistingCache() throws Exception {
-        ConcurrentMap concurrentMap = createRoutingTableCache();
+    routes.add(new String()); //can not be modified; should throw
+  }
 
-        //OK here we should try creating again the cache but this time it should return the existing one
-        when(ics.existCache(
-                RoutingTableImpl.ROUTING_TABLE_GLOBAL_CACHE)).thenReturn(true);
+  @Test
+  public void getRoutes_With2RoutesFor1RouteId_ShouldReturnASetWithSize2() throws Exception{
+    Assert.assertNotNull(routingTable);
+    RpcRouter.RouteIdentifier routeId = getRouteIdentifier();
+    routingTable.addRoute(routeId, "10.0.0.1:5555");
+    routingTable.addRoute(routeId, "10.0.0.2:5555");
 
-        when(ics.getCache(
-                RoutingTableImpl.ROUTING_TABLE_GLOBAL_CACHE)).thenReturn(concurrentMap);
+    Set<String> routes = routingTable.getRoutes(routeId); //returns Immutable Set
 
+    Assert.assertEquals(2, routes.size());
+  }
 
-        //here init
-        Component c = mock(Component.class);
+  @Test
+  public void getLastAddedRoute_WhenMultipleRoutesExists_ShouldReturnLatestRoute()
+    throws Exception {
 
-        rti.init(c);
+    Assert.assertNotNull(routingTable);
+    RpcRouter.RouteIdentifier routeId = getRouteIdentifier();
+    String route_1 = "10.0.0.1:5555";
+    String route_2 = "10.0.0.2:5555";
+    routingTable.addRoute(routeId, route_1);
+    routingTable.addRoute(routeId, route_2);
 
-        Assert.assertEquals(concurrentMap,rti.getRoutingTableCache());
+    Assert.assertEquals(route_2, routingTable.getLastAddedRoute(routeId));
+  }
 
+  @Test
+  public void removeRoute_WhenMultipleRoutesExist_RemovesGivenRoute() throws Exception{
+    Assert.assertNotNull(routingTable);
+    RpcRouter.RouteIdentifier routeId = getRouteIdentifier();
+    String route_1 = "10.0.0.1:5555";
+    String route_2 = "10.0.0.2:5555";
 
+    routingTable.addRoute(routeId, route_1);
+    routingTable.addRoute(routeId, route_2);
 
+    Assert.assertEquals(2, routingTable.getRoutes(routeId).size());
 
+    routingTable.removeRoute(routeId, route_1);
+    Assert.assertEquals(1, routingTable.getRoutes(routeId).size());
 
-    }
+  }
 
-    private class RouteChangeListenerImpl<I,R> implements RouteChangeListener<I,R>{
+  @Test
+  public void removeRoute_WhenOnlyOneRouteExists_RemovesRouteId() throws Exception{
+    Assert.assertNotNull(routingTable);
+    RpcRouter.RouteIdentifier routeId = getRouteIdentifier();
+    String route_1 = "10.0.0.1:5555";
 
-        @Override
-        public void onRouteUpdated(I key, R new_value) {
-            //To change body of implemented methods use File | Settings | File Templates.
-        }
+    routingTable.addRoute(routeId, route_1);
+    Assert.assertEquals(1, routingTable.getRoutes(routeId).size());
 
-        @Override
-        public void onRouteDeleted(I key) {
-            //To change body of implemented methods use File | Settings | File Templates.
-        }
-    }
+    routingTable.removeRoute(routeId, route_1);
+    ConcurrentMap cache = routingTable.getRpcCache();
+    Assert.assertFalse(cache.containsKey(routeId));
+
+  }
 
+  /*
+   * Private helper methods
+   */
+  private void createRoutingTableCache() throws Exception {
+
+    //here init
+    Component c = mock(Component.class);
+
+    when(clusterService.existCache(
+        RoutingTableImpl.GLOBALRPC_CACHE)).thenReturn(false);
+
+    when(clusterService.createCache(RoutingTableImpl.GLOBALRPC_CACHE,
+        EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).
+        thenReturn(mockGlobalRpcCache);
+
+    when(clusterService.existCache(
+        RoutingTableImpl.RPC_CACHE)).thenReturn(false);
+
+    when(clusterService.createCache(RoutingTableImpl.RPC_CACHE,
+        EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).
+        thenReturn(mockRpcCache);
+
+    doNothing().when(clusterService).tbegin();
+    doNothing().when(clusterService).tcommit();
+
+    routingTable.setClusterGlobalServices(this.clusterService);
+    routingTable.init(c);
+
+    Assert.assertEquals(mockGlobalRpcCache, routingTable.getGlobalRpcCache());
+    Assert.assertEquals(mockRpcCache, routingTable.getRpcCache());
+  }
+
+  private RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> getRouteIdentifier(){
+    RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier = mock(RpcRouter.RouteIdentifier.class);
+    InstanceIdentifier identifier = mock(InstanceIdentifier.class);
+    when(routeIdentifier.getType()).thenReturn(QNAME);
+    when(routeIdentifier.getRoute()).thenReturn(identifier);
+
+    return routeIdentifier;
+  }
+
+  private Runnable addRoutes(final int numRoutes, final String routePrefix, final RpcRouter.RouteIdentifier routeId){
+    return new Runnable() {
+      @Override
+      public void run() {
+        for (int i=0;i<numRoutes;i++){
+          String route = routePrefix + i;
+          try {
+            routingTable.addRoute(routeId, route);
+          } catch (Exception e) {
+            e.printStackTrace();
+          }
+        }
+      }
+    };
+  }
 }
index aa846ff78db2dd4a71ea77087978c559879ec654..65f1ff2fe368ac07255d852e57c58ee2e5e1f610 100644 (file)
@@ -7,24 +7,19 @@
  */
 package org.opendaylight.controller.sal.binding.api.data;
 
-import java.util.concurrent.Future;
-
 import org.opendaylight.controller.md.sal.common.api.data.DataChangePublisher;
 import org.opendaylight.controller.md.sal.common.api.data.DataModificationTransactionFactory;
 import org.opendaylight.controller.md.sal.common.api.data.DataReader;
 import org.opendaylight.controller.sal.binding.api.BindingAwareService;
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.DataRoot;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.common.RpcResult;
 
 /**
  * DataBrokerService provides unified access to the data stores available in the
  * system.
- * 
- * 
+ *
+ *
  * @see DataProviderService
  */
 public interface DataBrokerService extends //
@@ -32,163 +27,37 @@ public interface DataBrokerService extends //
         DataModificationTransactionFactory<InstanceIdentifier<? extends DataObject>, DataObject>, //
         DataReader<InstanceIdentifier<? extends DataObject>, DataObject>, //
         DataChangePublisher<InstanceIdentifier<? extends DataObject>, DataObject, DataChangeListener> {
-
-    /**
-     * Returns a data from specified Data Store.
-     * 
-     * Returns all the data visible to the consumer from specified Data Store.
-     * 
-     * @param <T>
-     *            Interface generated from YANG module representing root of data
-     * @param store
-     *            Identifier of the store, from which will be data retrieved
-     * @return data visible to the consumer
-     */
-    @Deprecated
-    <T extends DataRoot> T getData(DataStoreIdentifier store, Class<T> rootType);
-
-    /**
-     * Returns a filtered subset of data from specified Data Store.
-     * 
-     * <p>
-     * The filter is modeled as an hierarchy of Java TOs starting with
-     * implementation of {@link DataRoot} representing data root. The semantics
-     * of the filter tree is the same as filter semantics defined in the NETCONF
-     * protocol for rpc operations <code>get</code> and <code>get-config</code>
-     * in Section 6 of RFC6241.
-     * 
-     * 
-     * @see http://tools.ietf.org/html/rfc6241#section-6
-     * @param <T>
-     *            Interface generated from YANG module representing root of data
-     * @param store
-     *            Identifier of the store, from which will be data retrieved
-     * @param filter
-     *            Data tree filter similar to the NETCONF filter
-     * @return
-     */
-    @Deprecated
-    <T extends DataRoot> T getData(DataStoreIdentifier store, T filter);
-
-    /**
-     * Returns a candidate data which are not yet commited.
-     * 
-     * 
-     * @param <T>
-     *            Interface generated from YANG module representing root of data
-     * @param store
-     *            Identifier of the store, from which will be data retrieved
-     * @return
-     */
-    @Deprecated
-    <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, Class<T> rootType);
-
-    /**
-     * Returns a filtered subset of candidate data from specified Data Store.
-     * 
-     * <p>
-     * The filter is modeled as an hierarchy of {@link Node} starting with
-     * {@link CompositeNode} representing data root. The semantics of the filter
-     * tree is the same as filter semantics defined in the NETCONF protocol for
-     * rpc operations <code>get</code> and <code>get-config</code> in Section 6
-     * of RFC6241.
-     * 
-     * 
-     * @see http://tools.ietf.org/html/rfc6241#section-6
-     * @param <T>
-     *            Interface generated from YANG module representing root of data
-     * @param store
-     *            Identifier of the store, from which will be data retrieved
-     * @param filter
-     *            A filter data root
-     * @return
-     */
-    @Deprecated
-    <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, T filter);
-
-    /**
-     * 
-     * @param <T>
-     *            Interface generated from YANG module representing root of data
-     * @param store
-     *            Identifier of the store, in which will be the candidate data
-     *            modified
-     * @param changeSet
-     *            Modification of data tree.
-     * @return Result object containing the modified data tree if the operation
-     *         was successful, otherwise list of the encountered errors.
-     */
-    @Deprecated
-    RpcResult<DataRoot> editCandidateData(DataStoreIdentifier store, DataRoot changeSet);
-
-    /**
-     * Initiates a two-phase commit of candidate data.
-     * 
-     * <p>
-     * The {@link Consumer} could initiate a commit of candidate data
-     * 
-     * <p>
-     * The successful commit changes the state of the system and may affect
-     * several components.
-     * 
-     * <p>
-     * The effects of successful commit of data are described in the
-     * specifications and YANG models describing the {@link Provider} components
-     * of controller. It is assumed that {@link Consumer} has an understanding
-     * of this changes.
-     * 
-     * 
-     * @see DataCommitHandler for further information how two-phase commit is
-     *      processed.
-     * @param store
-     *            Identifier of the store, where commit should occur.
-     * @return Result of the commit, containing success information or list of
-     *         encountered errors, if commit was not successful.
-     */
-    @Deprecated
-    Future<RpcResult<Void>> commit(DataStoreIdentifier store);
-
-    @Deprecated
-    DataObject getData(InstanceIdentifier<? extends DataObject> data);
-
-    @Deprecated
-    DataObject getConfigurationData(InstanceIdentifier<?> data);
     /**
      * Creates a data modification transaction.
-     * 
+     *
      * @return new blank data modification transaction.
      */
-    DataModificationTransaction beginTransaction();
-
-    @Deprecated
-    public void registerChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener);
-
-    @Deprecated
-    public void unregisterChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener);
+    @Override
+       DataModificationTransaction beginTransaction();
 
     /**
-     * Reads data subtree from configurational store. 
-     * (Store which is populated by consumer, which is usually used to 
+     * Reads data subtree from configurational store.
+     * (Store which is populated by consumer, which is usually used to
      * inject state into providers. E.g. Flow configuration)-
-     * 
+     *
      */
     @Override
     public DataObject readConfigurationData(InstanceIdentifier<? extends DataObject> path);
-    
+
     /**
-     * Reads data subtree from operational store. 
-     * (Store which is populated by providers, which is usually used to 
+     * Reads data subtree from operational store.
+     * (Store which is populated by providers, which is usually used to
      * capture state of providers. E.g. Topology)
-     * 
+     *
      */
     @Override
     public DataObject readOperationalData(InstanceIdentifier<? extends DataObject> path);
-    
+
     /**
-     * Register a data change listener for particular subtree. 
-     * 
+     * Register a data change listener for particular subtree.
+     *
      * Callback is invoked each time data in subtree changes.
-     * 
+     *
      */
     @Override
     public ListenerRegistration<DataChangeListener> registerDataChangeListener(
index 28ffff8b2d0a368b3a9843c3591151bcb996d7a9..ad4a1ee200501ceaa5d5647a5f507afbd19e61e2 100644 (file)
@@ -19,7 +19,6 @@
             <plugin>
                 <groupId>org.opendaylight.yangtools</groupId>
                 <artifactId>yang-maven-plugin</artifactId>
-                <version>${yangtools.version}</version>
                 <executions>
                     <execution>
                         <goals>
@@ -51,7 +50,7 @@
                     <dependency>
                         <groupId>org.opendaylight.controller</groupId>
                         <artifactId>yang-jmx-generator-plugin</artifactId>
-                        <version>0.2.4-SNAPSHOT</version>
+                        <version>${config.version}</version>
                     </dependency>
                     <dependency>
                         <groupId>org.opendaylight.yangtools</groupId>
index 16d5a24cb5b7c80364edd8dd5dbe4f8b59e6aa97..48ccbfbc955ff9163487fca3523a184cf9d1c688 100644 (file)
@@ -9,19 +9,15 @@ package org.opendaylight.controller.sal.binding.impl;
 \r
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.concurrent.Future;
 import java.util.concurrent.atomic.AtomicLong;
 
 import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataBroker;
 import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
 import org.opendaylight.controller.sal.binding.impl.util.BindingAwareDataReaderRouter;
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.DataRoot;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.util.DataObjectReadingUtil;
-import org.opendaylight.yangtools.yang.common.RpcResult;
 
 import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableMap;
@@ -79,68 +75,7 @@ public class DataBrokerImpl extends AbstractDataBroker<InstanceIdentifier<? exte
     }\r
 \r
     @Override\r
-    @Deprecated\r
-    public <T extends DataRoot> T getData(DataStoreIdentifier store, Class<T> rootType) {\r
-        throw new UnsupportedOperationException("Deprecated");\r
-    }\r
-\r
-    @Override\r
-    @Deprecated\r
-    public <T extends DataRoot> T getData(DataStoreIdentifier store, T filter) {\r
-        throw new UnsupportedOperationException("Deprecated");\r
-    }\r
-\r
-    @Override\r
-    @Deprecated\r
-    public <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, Class<T> rootType) {\r
-        throw new UnsupportedOperationException("Deprecated");\r
-    }\r
-\r
-    @Override\r
-    @Deprecated\r
-    public <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, T filter) {\r
-        throw new UnsupportedOperationException("Deprecated");\r
-    }\r
-\r
-    @Override\r
-    @Deprecated\r
-    public RpcResult<DataRoot> editCandidateData(DataStoreIdentifier store, DataRoot changeSet) {\r
-        throw new UnsupportedOperationException("Deprecated");\r
-    }\r
-\r
-    @Override\r
-    @Deprecated\r
-    public Future<RpcResult<Void>> commit(DataStoreIdentifier store) {\r
-        throw new UnsupportedOperationException("Deprecated");\r
-    }\r
-\r
-    @Override\r
-    @Deprecated\r
-    public DataObject getData(InstanceIdentifier<? extends DataObject> data) {\r
-        throw new UnsupportedOperationException("Deprecated");\r
-    }\r
-\r
-    @Override\r
-    @Deprecated\r
-    public DataObject getConfigurationData(InstanceIdentifier<?> data) {\r
-        throw new UnsupportedOperationException("Deprecated");\r
-    }\r
-\r
-    @Override\r
-    @Deprecated\r
-    public void registerChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener) {\r
-        throw new UnsupportedOperationException("Deprecated");\r
-    }\r
-\r
-    @Override\r
-    @Deprecated\r
-    public void unregisterChangeListener(InstanceIdentifier<? extends DataObject> path,\r
-            DataChangeListener changeListener) {\r
-        throw new UnsupportedOperationException("Deprecated");\r
-    }\r
-\r
-    @Override\r
-    public void close() throws Exception {\r
+    public void close() {\r
 \r
     }
 
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DeprecatedDataAPISupport.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DeprecatedDataAPISupport.xtend
deleted file mode 100644 (file)
index ee2ade5..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.binding.impl
-
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService
-import org.opendaylight.controller.sal.common.DataStoreIdentifier
-import org.opendaylight.yangtools.yang.binding.DataRoot
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.controller.sal.binding.api.data.DataChangeListener
-
-abstract class DeprecatedDataAPISupport implements DataProviderService {
-
-    @Deprecated
-    override commit(DataStoreIdentifier store) {
-        throw new UnsupportedOperationException("Deprecated")
-    }
-
-    @Deprecated
-    override editCandidateData(DataStoreIdentifier store, DataRoot changeSet) {
-        throw new UnsupportedOperationException("Deprecated")
-    }
-
-    @Deprecated
-    override <T extends DataRoot> getCandidateData(DataStoreIdentifier store, Class<T> rootType) {
-        throw new UnsupportedOperationException("Deprecated")
-    }
-
-    @Deprecated
-    override <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, T filter) {
-        throw new UnsupportedOperationException("Deprecated")
-    }
-
-    @Deprecated
-    override getConfigurationData(InstanceIdentifier<?> data) {
-        throw new UnsupportedOperationException("Deprecated")
-    }
-
-    @Deprecated
-    override <T extends DataRoot> getData(DataStoreIdentifier store, Class<T> rootType) {
-        throw new UnsupportedOperationException("Deprecated")
-    }
-
-    @Deprecated
-    override <T extends DataRoot> T getData(DataStoreIdentifier store, T filter) {
-        throw new UnsupportedOperationException("Deprecated")
-    }
-
-    @Deprecated
-    override getData(InstanceIdentifier<? extends DataObject> path) {
-        return readOperationalData(path);
-    }
-
-    override registerChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener) {
-    }
-
-    override unregisterChangeListener(InstanceIdentifier<? extends DataObject> path,
-        DataChangeListener changeListener) {
-    }
-
-}
index e48ebbc0577f1b6101a772284ba9e07b3e6580cf..e6e935c920b613c577d4b9f890092a22c13cb49d 100644 (file)
@@ -202,6 +202,16 @@ public class BindingIndependentConnector implements //
             DataModification<InstanceIdentifier<? extends DataObject>, DataObject> source) {
         DataModificationTransaction target = biDataService.beginTransaction();
         LOG.debug("Created DOM Transaction {} for {},", target.getIdentifier(),source.getIdentifier());
+        for (InstanceIdentifier<? extends DataObject> entry : source.getRemovedConfigurationData()) {
+            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry);
+            target.removeConfigurationData(biEntry);
+            LOG.debug("Delete of Binding Configuration Data {} is translated to {}",entry,biEntry);
+        }
+        for (InstanceIdentifier<? extends DataObject> entry : source.getRemovedOperationalData()) {
+            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry);
+            target.removeOperationalData(biEntry);
+            LOG.debug("Delete of Binding Operational Data {} is translated to {}",entry,biEntry);
+        }
         for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : source.getUpdatedConfigurationData()
                 .entrySet()) {
             Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> biEntry = mappingService
@@ -216,16 +226,7 @@ public class BindingIndependentConnector implements //
             target.putOperationalData(biEntry.getKey(), biEntry.getValue());
             LOG.debug("Update of Binding Operational Data {} is translated to {}",entry,biEntry);
         }
-        for (InstanceIdentifier<? extends DataObject> entry : source.getRemovedConfigurationData()) {
-            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry);
-            target.removeConfigurationData(biEntry);
-            LOG.debug("Delete of Binding Configuration Data {} is translated to {}",entry,biEntry);
-        }
-        for (InstanceIdentifier<? extends DataObject> entry : source.getRemovedOperationalData()) {
-            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biEntry = mappingService.toDataDom(entry);
-            target.removeOperationalData(biEntry);
-            LOG.debug("Delete of Binding Operational Data {} is translated to {}",entry,biEntry);
-        }
+
         return target;
     }
 
@@ -233,6 +234,24 @@ public class BindingIndependentConnector implements //
             DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> source) {
         org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction target = baDataService
                 .beginTransaction();
+        for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedConfigurationData()) {
+            try {
+
+                InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
+                target.removeConfigurationData(baEntry);
+            } catch (DeserializationException e) {
+                LOG.error("Ommiting from BA transaction: {}.", entry, e);
+            }
+        }
+        for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedOperationalData()) {
+            try {
+
+                InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
+                target.removeOperationalData(baEntry);
+            } catch (DeserializationException e) {
+                LOG.error("Ommiting from BA transaction: {}.", entry, e);
+            }
+        }
         for (Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> entry : source
                 .getUpdatedConfigurationData().entrySet()) {
             try {
@@ -254,24 +273,6 @@ public class BindingIndependentConnector implements //
                 LOG.error("Ommiting from BA transaction: {}.", entry.getKey(), e);
             }
         }
-        for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedConfigurationData()) {
-            try {
-
-                InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
-                target.removeConfigurationData(baEntry);
-            } catch (DeserializationException e) {
-                LOG.error("Ommiting from BA transaction: {}.", entry, e);
-            }
-        }
-        for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry : source.getRemovedOperationalData()) {
-            try {
-
-                InstanceIdentifier<?> baEntry = mappingService.fromDataDom(entry);
-                target.removeOperationalData(baEntry);
-            } catch (DeserializationException e) {
-                LOG.error("Ommiting from BA transaction: {}.", entry, e);
-            }
-        }
         return target;
     }
 
index cb71b4fd3a5bf23646137b512df69a20314bb2f9..a58df8435b8f85d5b54f718cae4f4ff27d088af7 100644 (file)
@@ -24,7 +24,6 @@
             <plugin>
                 <groupId>org.opendaylight.yangtools</groupId>
                 <artifactId>yang-maven-plugin</artifactId>
-                <version>${yangtools.version}</version>
                 <executions>
                     <execution>
                         <goals>
                     <dependency>
                         <groupId>org.opendaylight.controller</groupId>
                         <artifactId>yang-jmx-generator-plugin</artifactId>
-                        <version>0.2.4-SNAPSHOT</version>
+                        <version>${config.version}</version>
                     </dependency>
                     <dependency>
                         <groupId>org.opendaylight.yangtools</groupId>
                         <artifactId>maven-sal-api-gen-plugin</artifactId>
-                       <version>${yangtools.version}</version>
+                        <version>${yangtools.version}</version>
                         <type>jar</type>
                     </dependency>
                 </dependencies>
diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/WriteParentReadChildTest.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/WriteParentReadChildTest.java
new file mode 100644 (file)
index 0000000..35b4e92
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.binding.test.bugfix;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+import com.google.common.collect.ImmutableList;
+
+public class WriteParentReadChildTest extends AbstractDataServiceTest {
+
+    private static final String FLOW_ID = "1234";
+    private static final short TABLE_ID = (short) 0;
+    private static final String NODE_ID = "node:1";
+
+    private static final NodeKey NODE_KEY = new NodeKey(new NodeId(NODE_ID));
+    private static final FlowKey FLOW_KEY = new FlowKey(new FlowId(FLOW_ID));
+    private static final TableKey TABLE_KEY = new TableKey(TABLE_ID);
+
+    private static final InstanceIdentifier<Node> NODE_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) //
+            .child(Node.class, NODE_KEY).toInstance();
+
+    private static final InstanceIdentifier<Table> TABLE_INSTANCE_ID_BA = //
+    InstanceIdentifier.builder(NODE_INSTANCE_ID_BA) //
+            .augmentation(FlowCapableNode.class).child(Table.class, TABLE_KEY).build();
+
+    private static final InstanceIdentifier<? extends DataObject> FLOW_INSTANCE_ID_BA = //
+    InstanceIdentifier.builder(TABLE_INSTANCE_ID_BA) //
+            .child(Flow.class, FLOW_KEY) //
+            .toInstance();
+    /**
+     *
+     * The scenario tests writing parent node, which also contains child items
+     * and then reading child directly, by specifying path to the child.
+     *
+     * Expected behaviour is child is returned.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void writeTableReadFlow() throws Exception {
+
+        DataModificationTransaction modification = baDataService.beginTransaction();
+
+        Flow flow = new FlowBuilder() //
+                .setKey(FLOW_KEY) //
+                .setMatch(new MatchBuilder() //
+                        .setVlanMatch(new VlanMatchBuilder() //
+                                .setVlanId(new VlanIdBuilder() //
+                                        .setVlanId(new VlanId(10)) //
+                                        .build()) //
+                                .build()) //
+                        .build()) //
+                        .setInstructions(new InstructionsBuilder() //
+                            .setInstruction(ImmutableList.<Instruction>builder() //
+                                    .build()) //
+                        .build()) //
+                .build();
+
+        Table table = new TableBuilder()
+            .setKey(TABLE_KEY)
+            .setFlow(ImmutableList.of(flow))
+        .build();
+
+        modification.putConfigurationData(TABLE_INSTANCE_ID_BA, table);
+        RpcResult<TransactionStatus> ret = modification.commit().get();
+        assertNotNull(ret);
+        assertEquals(TransactionStatus.COMMITED, ret.getResult());
+
+        DataObject readedTable = baDataService.readConfigurationData(TABLE_INSTANCE_ID_BA);
+        assertNotNull("Readed table should not be nul.", readedTable);
+        assertTrue(readedTable instanceof Table);
+        
+        DataObject readedFlow = baDataService.readConfigurationData(FLOW_INSTANCE_ID_BA);
+        assertNotNull("Readed flow should not be null.",readedFlow);
+        assertTrue(readedFlow instanceof Flow);
+        assertEquals(flow, readedFlow);
+
+    }
+}
\ No newline at end of file
index 9bc8a482145e120d10857a136d35caf1ec693121..213e4f47f759026215fb7824dc214eb092c7416d 100644 (file)
 
 
     <dependencies>
+        <!--Compile scopes for all testing dependencies are intentional-->
+        <!--This way, all testing dependencies can be transitively used by other integration test modules-->
+        <!--If the dependencies are test scoped, they are not visible to other maven modules depending on sal-binding-it-->
 
+        <!--TODO Create generic utilities(extract from this module) for integration tests on the controller-->
         <dependency>
             <groupId>org.opendaylight.yangtools.thirdparty</groupId>
             <artifactId>xtend-lib-osgi</artifactId>
             <version>2.4.3</version>
-            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>sal-binding-broker-impl</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.ops4j.pax.exam</groupId>
             <artifactId>pax-exam-container-native</artifactId>
-            <scope>test</scope>
+            <scope>compile</scope>
         </dependency>
         <dependency>
             <groupId>org.ops4j.pax.exam</groupId>
             <artifactId>pax-exam-junit4</artifactId>
-            <scope>test</scope>
+            <scope>compile</scope>
         </dependency>
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>config-netconf-connector</artifactId>
-            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
         <dependency>
             <groupId>org.ops4j.pax.exam</groupId>
             <artifactId>pax-exam-link-mvn</artifactId>
-            <scope>test</scope>
+            <scope>compile</scope>
         </dependency>
         <dependency>
             <groupId>equinoxSDK381</groupId>
             <artifactId>org.eclipse.osgi</artifactId>
-            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
         <dependency>
             <groupId>org.mockito</groupId>
             <artifactId>mockito-all</artifactId>
-            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.opendaylight.controller.model</groupId>
index 77b411002b01e480bca055c7507ef59c0915d834..64c1ad3ab4035e173858dfacbae6536567aece93 100644 (file)
@@ -7,23 +7,18 @@
  */
 package org.opendaylight.controller.md.sal.binding.util;
 
-import java.util.concurrent.Future;
-
 import org.opendaylight.controller.sal.binding.api.NotificationListener;
 import org.opendaylight.controller.sal.binding.api.NotificationService;
 import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry;
 import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
 import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.concepts.Registration;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.DataRoot;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.Notification;
 import org.opendaylight.yangtools.yang.binding.RpcService;
-import org.opendaylight.yangtools.yang.common.RpcResult;
 
 import com.google.common.base.Preconditions;
 
@@ -114,72 +109,11 @@ public abstract class AbstractBindingSalConsumerInstance<D extends DataBrokerSer
         return getNotificationBrokerChecked().registerNotificationListener(listener);
     }
 
-    @Override
-    @Deprecated
-    public <T extends DataRoot> T getData(DataStoreIdentifier store, Class<T> rootType) {
-        return getDataBrokerChecked().getData(store, rootType);
-    }
-
-    @Override
-    @Deprecated
-    public <T extends DataRoot> T getData(DataStoreIdentifier store, T filter) {
-        return getDataBrokerChecked().getData(store, filter);
-    }
-
-    @Override
-    @Deprecated
-    public <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, Class<T> rootType) {
-        return getDataBrokerChecked().getCandidateData(store, rootType);
-    }
-
-    @Override
-    @Deprecated
-    public <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, T filter) {
-        return getDataBrokerChecked().getCandidateData(store, filter);
-    }
-
-    @Override
-    @Deprecated
-    public RpcResult<DataRoot> editCandidateData(DataStoreIdentifier store, DataRoot changeSet) {
-        return getDataBrokerChecked().editCandidateData(store, changeSet);
-    }
-
-    @Override
-    @Deprecated
-    public Future<RpcResult<Void>> commit(DataStoreIdentifier store) {
-        return getDataBrokerChecked().commit(store);
-    }
-
-    @Override
-    @Deprecated
-    public DataObject getData(InstanceIdentifier<? extends DataObject> data) {
-        return getDataBrokerChecked().getData(data);
-    }
-
-    @Override
-    @Deprecated
-    public DataObject getConfigurationData(InstanceIdentifier<?> data) {
-        return getDataBrokerChecked().getConfigurationData(data);
-    }
-
     @Override
     public DataModificationTransaction beginTransaction() {
         return getDataBrokerChecked().beginTransaction();
     }
 
-    @Override
-    @Deprecated
-    public void registerChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener) {
-        getDataBrokerChecked().registerChangeListener(path, changeListener);
-    }
-
-    @Override
-    @Deprecated
-    public void unregisterChangeListener(InstanceIdentifier<? extends DataObject> path,
-            DataChangeListener changeListener) {
-        getDataBrokerChecked().unregisterChangeListener(path, changeListener);
-    }
-
     @Override
     @Deprecated
     public DataObject readConfigurationData(InstanceIdentifier<? extends DataObject> path) {
index 939ff9513513ff1de802746facfdd09844952b76..30f4fc03cb18b13e0d518c7b237f10e471a190f6 100644 (file)
@@ -24,8 +24,8 @@ import org.opendaylight.yangtools.yang.common.RpcResult;
  * this is responsibility of the coordinator (broker or some component of the
  * broker).
  *
- * The commit handlers are responsible for changing the internal state of the
- * provider to reflect the commited changes in data.
+ * Commit handlers are responsible for changing the internal state of the
+ * provider to reflect the committed changes in data.
  *
  * <h3>Two-phase commit</h3>
  *
index 33de1d83dae3cf40ff875625b979a3182783cf20..e201f8835b84182a9f22e9c712a2f8cc0073836f 100644 (file)
@@ -59,7 +59,7 @@ public class TwoPhaseCommit<P extends Path<P>, D extends Object, DCL extends Dat
                 .addAll(transaction.getCreatedOperationalData().keySet())
                 .addAll(transaction.getRemovedOperationalData()).build();
 
-        log.trace("Transaction: {} Affected Subtrees:", transactionId, changedPaths);
+        log.trace("Transaction: {} Affected Subtrees: {}", transactionId, changedPaths);
 
         // The transaction has no effects, let's just shortcut it
         if (changedPaths.isEmpty()) {
@@ -124,7 +124,7 @@ public class TwoPhaseCommit<P extends Path<P>, D extends Object, DCL extends Dat
 
         captureFinalState(listeners);
 
-        log.trace("Transaction: {} Notifying listeners.");
+        log.trace("Transaction: {} Notifying listeners.", transactionId);
 
         publishDataChangeEvent(listeners);
         return Rpcs.<TransactionStatus> getRpcResult(true, TransactionStatus.COMMITED,
index 42b00ba03d113dbcf0eb67958f068d5370491792..3384e8fb20037d0e9da1e020bf9ae2e744cc24a8 100644 (file)
@@ -12,6 +12,10 @@ import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
+/**
+ * @deprecated Use {@link com.google.common.util.concurrent.Futures} instead.
+ */
+@Deprecated
 public class Futures {
 
     private Futures() {
index 9c253eecb8383d6ee5d6fe7259e81d506656686f..9eadce3ed7cb0d35885f3239637ee0478b150002 100644 (file)
@@ -22,7 +22,6 @@
             <plugin>
                 <groupId>org.opendaylight.yangtools</groupId>
                 <artifactId>yang-maven-plugin</artifactId>
-                <version>${yangtools.version}</version>
                 <executions>
                     <execution>
                         <goals>
@@ -54,7 +53,7 @@
                     <dependency>
                         <groupId>org.opendaylight.controller</groupId>
                         <artifactId>yang-jmx-generator-plugin</artifactId>
-                        <version>0.2.4-SNAPSHOT</version>
+                        <version>${config.version}</version>
                     </dependency>
                     <dependency>
                         <groupId>org.opendaylight.yangtools</groupId>
index f7c46086e301ac9309bb435921388b97a39cd4a2..6af06255c7ef3adbbfd526404babf70b4b285a6b 100644 (file)
@@ -25,16 +25,16 @@ import org.osgi.framework.BundleContext;
 
 /**
  * Core component of the SAL layer responsible for wiring the SAL consumers.
- * 
+ *
  * The responsibility of the broker is to maintain registration of SAL
  * functionality {@link Consumer}s and {@link Provider}s, store provider and
  * consumer specific context and functionality registration via
  * {@link ConsumerSession} and provide access to infrastructure services, which
  * removes direct dependencies between providers and consumers.
- * 
- * 
+ *
+ *
  * <h3>Infrastructure services</h3> Some examples of infrastructure services:
- * 
+ *
  * <ul>
  * <li>RPC Invocation - see {@link ConsumerSession#rpc(QName, CompositeNode)},
  * {@link ProviderSession#addRpcImplementation(QName, RpcImplementation)} and
@@ -45,41 +45,41 @@ import org.osgi.framework.BundleContext;
  * <li>Data Store access and modification - see {@link DataBrokerService} and
  * {@link DataProviderService}
  * </ul>
- * 
+ *
  * The services are exposed via session.
- * 
+ *
  * <h3>Session-based access</h3>
- * 
+ *
  * The providers and consumers needs to register in order to use the
  * binding-independent SAL layer and to expose functionality via SAL layer.
- * 
+ *
  * For more information about session-based access see {@link ConsumerSession}
  * and {@link ProviderSession}
- * 
- * 
- * 
+ *
+ *
+ *
  */
 public interface Broker {
 
     /**
      * Registers the {@link Consumer}, which will use the SAL layer.
-     * 
+     *
      * <p>
      * During the registration, the broker obtains the initial functionality
      * from consumer, using the {@link Consumer#getConsumerFunctionality()}, and
      * register that functionality into system and concrete infrastructure
      * services.
-     * 
+     *
      * <p>
      * Note that consumer could register additional functionality at later point
      * by using service and functionality specific APIs.
-     * 
+     *
      * <p>
      * The consumer is required to use returned session for all communication
      * with broker or one of the broker services. The session is announced to
      * the consumer by invoking
      * {@link Consumer#onSessionInitiated(ConsumerSession)}.
-     * 
+     *
      * @param cons
      *            Consumer to be registered.
      * @param context
@@ -93,25 +93,25 @@ public interface Broker {
 
     /**
      * Registers the {@link Provider}, which will use the SAL layer.
-     * 
+     *
      * <p>
      * During the registration, the broker obtains the initial functionality
      * from consumer, using the {@link Provider#getProviderFunctionality()}, and
      * register that functionality into system and concrete infrastructure
      * services.
-     * 
+     *
      * <p>
      * Note that consumer could register additional functionality at later point
      * by using service and functionality specific APIs (e.g.
      * {@link ProviderSession#addRpcImplementation(QName, RpcImplementation)}
-     * 
+     *
      * <p>
      * The consumer is <b>required to use</b> returned session for all
      * communication with broker or one of the broker services. The session is
      * announced to the consumer by invoking
      * {@link Provider#onSessionInitiated(ProviderSession)}.
-     * 
-     * 
+     *
+     *
      * @param prov
      *            Provider to be registered.
      * @param context
@@ -125,25 +125,25 @@ public interface Broker {
 
     /**
      * {@link Consumer} specific access to the SAL functionality.
-     * 
+     *
      * <p>
      * ConsumerSession is {@link Consumer}-specific access to the SAL
      * functionality and infrastructure services.
-     * 
+     *
      * <p>
      * The session serves to store SAL context (e.g. registration of
      * functionality) for the consumer and provides access to the SAL
      * infrastructure services and other functionality provided by
      * {@link Provider}s.
-     * 
-     * 
-     * 
+     *
+     *
+     *
      */
     public interface ConsumerSession {
 
         /**
          * Sends an RPC to other components registered to the broker.
-         * 
+         *
          * @see RpcImplementation
          * @param rpc
          *            Name of RPC
@@ -158,7 +158,7 @@ public interface Broker {
         /**
          * Returns a session specific instance (implementation) of requested
          * service
-         * 
+         *
          * @param service
          *            Broker service
          * @return Session specific implementation of service
@@ -167,44 +167,44 @@ public interface Broker {
 
         /**
          * Closes a session between consumer and broker.
-         * 
+         *
          * <p>
          * The close operation unregisters a consumer and remove all registered
          * functionality of the consumer from the system.
-         * 
+         *
          */
         void close();
     }
 
     /**
      * {@link Provider} specific access to the SAL functionality.
-     * 
+     *
      * <p>
      * ProviderSession is {@link Provider}-specific access to the SAL
      * functionality and infrastructure services, which also allows for exposing
      * the provider's functionality to the other {@link Consumer}s.
-     * 
+     *
      * <p>
      * The session serves to store SAL context (e.g. registration of
      * functionality) for the providers and exposes access to the SAL
      * infrastructure services, dynamic functionality registration and any other
      * functionality provided by other {@link Provider}s.
-     * 
+     *
      */
     public interface ProviderSession extends ConsumerSession {
         /**
          * Registers an implementation of the rpc.
-         * 
+         *
          * <p>
          * The registered rpc functionality will be available to all other
          * consumers and providers registered to the broker, which are aware of
          * the {@link QName} assigned to the rpc.
-         * 
+         *
          * <p>
          * There is no assumption that rpc type is in the set returned by
          * invoking {@link RpcImplementation#getSupportedRpcs()}. This allows
          * for dynamic rpc implementations.
-         * 
+         *
          * @param rpcType
          *            Name of Rpc
          * @param implementation
@@ -221,7 +221,7 @@ public interface Broker {
 
         /**
          * Closes a session between provider and SAL.
-         * 
+         *
          * <p>
          * The close operation unregisters a provider and remove all registered
          * functionality of the provider from the system.
@@ -233,12 +233,15 @@ public interface Broker {
         boolean isClosed();
 
         Set<QName> getSupportedRpcs();
-        
+
         ListenerRegistration<RpcRegistrationListener> addRpcRegistrationListener(RpcRegistrationListener listener);
     }
 
     public interface RpcRegistration extends Registration<RpcImplementation> {
         QName getType();
+
+        @Override
+        void close();
     }
 
     public interface RoutedRpcRegistration extends RpcRegistration,
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RoutedRpcDefaultImplementation.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RoutedRpcDefaultImplementation.java
new file mode 100644 (file)
index 0000000..c8eb7fd
--- /dev/null
@@ -0,0 +1,12 @@
+package org.opendaylight.controller.sal.core.api;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+public interface RoutedRpcDefaultImplementation {
+
+  public RpcResult<CompositeNode> invokeRpc(QName rpc, InstanceIdentifier identifier, CompositeNode input);
+
+}
index 0299505cdeee6bcef00315507012cbd030f384c1..6b1030a81500f5a909d6df30f69e52208025c482 100644 (file)
@@ -16,11 +16,11 @@ import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 
 /**
- * {@link Provider}'s implementation of rpc.
- * 
- * In order to expose the rpc to other components, the provider MUST register
- * concrete implementation of this interface
- * 
+ * {@link Provider}'s implementation of an RPC.
+ *
+ * In order to expose an RPC to other components, the provider MUST register
+ * a concrete implementation of this interface.
+ *
  * The registration could be done by :
  * <ul>
  * <li>returning an instance of implementation in the return value of
@@ -29,9 +29,9 @@ import org.opendaylight.yangtools.yang.data.api.CompositeNode;
  * arguments to the
  * {@link ProviderSession#addRpcImplementation(QName, RpcImplementation)}
  * </ul>
- * 
+ *
  * The simplified process of the invocation of rpc is following:
- * 
+ *
  * <ol>
  * <li> {@link Consumer} invokes
  * {@link ConsumerSession#rpc(QName, CompositeNode)}
@@ -42,31 +42,31 @@ import org.opendaylight.yangtools.yang.data.api.CompositeNode;
  * {@link RpcResult}
  * <li> {@link Broker} returns the {@link RpcResult} to {@link Consumer}
  * </ol>
- * 
- * 
+ *
+ *
  */
 public interface RpcImplementation extends Provider.ProviderFunctionality {
 
     /**
      * A set of rpc types supported by implementation.
-     * 
+     *
      * The set of rpc {@link QName}s which are supported by this implementation.
      * This set is used, when {@link Provider} is registered to the SAL, to
      * register and expose the implementation of the returned rpcs.
-     * 
+     *
      * @return Set of QNames identifying supported RPCs
      */
     Set<QName> getSupportedRpcs();
 
     /**
      * Invokes a implementation of specified rpc.
-     * 
-     * 
+     *
+     *
      * @param rpc
      *            Rpc to be invoked
      * @param input
      *            Input data for rpc.
-     * 
+     *
      * @throws IllegalArgumentException
      *             <ul>
      *             <li>If rpc is null.
index 8a9d1678657c6b3555ba23d4a3c536cae5d3d30d..f43dcd6b43565692136eda0eecac5354b29681ac 100644 (file)
@@ -42,4 +42,13 @@ public interface RpcProvisionRegistry extends RpcImplementation, BrokerService,
     ListenerRegistration<RpcRegistrationListener> addRpcRegistrationListener(RpcRegistrationListener listener);
 
     RoutedRpcRegistration addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation);
+
+  /**
+   * Sets this RoutedRpc Implementation as a delegate rpc provider and will be asked to invoke rpc if the
+   * current provider can't service the rpc request
+   *
+   * @param defaultImplementation
+   *              Provider's implementation of RPC functionality
+   */
+    public void setRoutedRpcDefaultDelegate(RoutedRpcDefaultImplementation defaultImplementation);
 }
index d22b54ee19c2e1dde0b3f75f7f63ef3f7f3005e5..225281e7a400fa3aefb3c0d38c85b08c48b77daa 100644 (file)
@@ -63,7 +63,6 @@
             <plugin>
                 <groupId>org.opendaylight.yangtools</groupId>
                 <artifactId>yang-maven-plugin</artifactId>
-                <version>${yangtools.version}</version>
                 <executions>
                     <execution>
                         <goals>
@@ -95,7 +94,7 @@
                     <dependency>
                         <groupId>org.opendaylight.controller</groupId>
                         <artifactId>yang-jmx-generator-plugin</artifactId>
-                        <version>0.2.4-SNAPSHOT</version>
+                        <version>${config.version}</version>
                     </dependency>
                     <dependency>
                         <groupId>org.opendaylight.yangtools</groupId>
index 1159d5650e6599a72db0af912909244d17cf612b..6b5f5acb1945a872d48b925da58283e314014af4 100644 (file)
@@ -50,7 +50,7 @@ class BrokerConfigActivator implements AutoCloseable {
         broker.setRouter(new SchemaAwareRpcBroker("/", SchemaContextProviders.fromSchemaService(schemaService)));
 
         dataService = new DataBrokerImpl();
-        dataService.setExecutor(broker.getExecutor());
+        //dataService.setExecutor(broker.getExecutor());
 
         dataReg = context.registerService(DataBrokerService, dataService, emptyProperties);
         dataProviderReg = context.registerService(DataProviderService, dataService, emptyProperties);
index 3bbdab2c0722d656aba74035186faa4bc0d843aa..64de8683d1d1a8a5c3854aa5f55e6b907852c448 100644 (file)
@@ -14,21 +14,22 @@ import java.util.concurrent.Callable
 import java.util.concurrent.ExecutorService
 import java.util.concurrent.Executors
 import java.util.concurrent.Future
-import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener
 import org.opendaylight.controller.sal.core.api.Broker
 import org.opendaylight.controller.sal.core.api.Consumer
 import org.opendaylight.controller.sal.core.api.Provider
-import org.opendaylight.controller.sal.core.api.RpcImplementation
-import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry
-import org.opendaylight.controller.sal.core.api.RpcRegistrationListener
-import org.opendaylight.controller.sal.core.api.RpcRoutingContext
-import org.opendaylight.controller.sal.dom.broker.spi.RpcRouter
 import org.opendaylight.yangtools.yang.common.QName
 import org.opendaylight.yangtools.yang.common.RpcResult
 import org.opendaylight.yangtools.yang.data.api.CompositeNode
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
 import org.osgi.framework.BundleContext
 import org.slf4j.LoggerFactory
+import org.opendaylight.controller.sal.dom.broker.spi.RpcRouter
+import org.opendaylight.controller.sal.core.api.RpcRegistrationListener
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry
+import org.opendaylight.controller.sal.core.api.RpcImplementation
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener
+import org.opendaylight.controller.sal.core.api.RpcRoutingContext
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
+import org.opendaylight.controller.sal.core.api.RoutedRpcDefaultImplementation
 
 public class BrokerImpl implements Broker, RpcProvisionRegistry, AutoCloseable {
     private static val log = LoggerFactory.getLogger(BrokerImpl);
@@ -122,7 +123,11 @@ public class BrokerImpl implements Broker, RpcProvisionRegistry, AutoCloseable {
     override addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) {
         router.addRoutedRpcImplementation(rpcType,implementation);
     }
-    
+
+    override setRoutedRpcDefaultDelegate(RoutedRpcDefaultImplementation defaultImplementation) {
+        router.setRoutedRpcDefaultDelegate(defaultImplementation);
+    }
+
     override addRpcRegistrationListener(RpcRegistrationListener listener) {
         return router.addRpcRegistrationListener(listener);
     }
index a8bdddb5108d3ab0242024b7c3db4df3a1d1694a..5d93f4ee4d162b22a35c610d4f79b35e7cf66fb6 100644 (file)
@@ -19,6 +19,7 @@ import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener
 import org.opendaylight.controller.sal.common.DataStoreIdentifier;
 import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration;
 import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration;
+import org.opendaylight.controller.sal.core.api.RoutedRpcDefaultImplementation;
 import org.opendaylight.controller.sal.core.api.RpcImplementation;
 import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
 import org.opendaylight.controller.sal.core.api.RpcRoutingContext;
@@ -104,6 +105,11 @@ public class MountPointImpl implements MountProvisionInstance, SchemaContextProv
     }
 
     @Override
+    public void setRoutedRpcDefaultDelegate(RoutedRpcDefaultImplementation defaultImplementation) {
+      rpcs.setRoutedRpcDefaultDelegate(defaultImplementation);
+    }
+
+  @Override
     public RpcRegistration addRpcImplementation(QName rpcType, RpcImplementation implementation)
             throws IllegalArgumentException {
         return rpcs.addRpcImplementation(rpcType, implementation);
index 602afd7c0cf01d4bccc810e0b0dc2d1e5d9a0fd4..d8315568bee86ea07ee00b86feddcb0801faaa8e 100644 (file)
@@ -11,6 +11,9 @@ import static com.google.common.base.Preconditions.checkState;
 
 import java.util.ArrayList;
 import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 import java.util.Map.Entry;
 import java.util.concurrent.Future;
 
@@ -27,11 +30,13 @@ import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.SimpleNode;
 import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
-import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -41,7 +46,6 @@ import com.google.common.collect.ImmutableSet;
 
 public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator<DataStore> implements //
         DataStore, //
-        SchemaServiceListener, //
         SchemaContextListener, //
         AutoCloseable {
 
@@ -168,18 +172,25 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator<DataS
     private NormalizedDataModification prepareMergedTransaction(
             DataModification<InstanceIdentifier, CompositeNode> original) {
         NormalizedDataModification normalized = new NormalizedDataModification(original);
-        for (Entry<InstanceIdentifier, CompositeNode> entry : original.getUpdatedConfigurationData().entrySet()) {
-            normalized.putConfigurationData(entry.getKey(), entry.getValue());
-        }
-        for (Entry<InstanceIdentifier, CompositeNode> entry : original.getUpdatedOperationalData().entrySet()) {
-            normalized.putOperationalData(entry.getKey(), entry.getValue());
-        }
+        LOG.trace("Transaction: {} Removed Configuration {}, Removed Operational {}", original.getIdentifier(),
+                original.getRemovedConfigurationData(), original.getRemovedConfigurationData());
+        LOG.trace("Transaction: {} Created Configuration {}, Created Operational {}", original.getIdentifier(),
+                original.getCreatedConfigurationData().entrySet(), original.getCreatedOperationalData().entrySet());
+        LOG.trace("Transaction: {} Updated Configuration {}, Updated Operational {}", original.getIdentifier(),
+                original.getUpdatedConfigurationData().entrySet(), original.getUpdatedOperationalData().entrySet());
+
         for (InstanceIdentifier entry : original.getRemovedConfigurationData()) {
             normalized.deepRemoveConfigurationData(entry);
         }
         for (InstanceIdentifier entry : original.getRemovedOperationalData()) {
             normalized.deepRemoveOperationalData(entry);
         }
+        for (Entry<InstanceIdentifier, CompositeNode> entry : original.getUpdatedConfigurationData().entrySet()) {
+            normalized.putDeepConfigurationData(entry.getKey(), entry.getValue());
+        }
+        for (Entry<InstanceIdentifier, CompositeNode> entry : original.getUpdatedOperationalData().entrySet()) {
+            normalized.putDeepOperationalData(entry.getKey(), entry.getValue());
+        }
         return normalized;
     }
 
@@ -310,6 +321,8 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator<DataS
 
     private class NormalizedDataModification extends AbstractDataModification<InstanceIdentifier, CompositeNode> {
 
+        private final String CONFIGURATIONAL_DATA_STORE_MARKER = "configurational";
+        private final String OPERATIONAL_DATA_STORE_MARKER = "operational";
         private final Object identifier;
         private TransactionStatus status;
 
@@ -342,6 +355,14 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator<DataS
             }
         }
 
+        public void putDeepConfigurationData(InstanceIdentifier entryKey, CompositeNode entryData) {
+            this.putCompositeNodeData(entryKey, entryData, CONFIGURATIONAL_DATA_STORE_MARKER);
+        }
+
+        public void putDeepOperationalData(InstanceIdentifier entryKey, CompositeNode entryData) {
+            this.putCompositeNodeData(entryKey, entryData, OPERATIONAL_DATA_STORE_MARKER);
+        }
+
         @Override
         public Object getIdentifier() {
             return this.identifier;
@@ -368,6 +389,72 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator<DataS
                 CompositeNode modified) {
             return mergeData(path, stored, modified, false);
         }
-    }
 
+        private void putData(InstanceIdentifier entryKey, CompositeNode entryData, String dataStoreIdentifier) {
+            if (dataStoreIdentifier != null && entryKey != null && entryData != null) {
+                switch (dataStoreIdentifier) {
+                case (CONFIGURATIONAL_DATA_STORE_MARKER):
+                    this.putConfigurationData(entryKey, entryData);
+                    break;
+                case (OPERATIONAL_DATA_STORE_MARKER):
+                    this.putOperationalData(entryKey, entryData);
+                    break;
+
+                default:
+                    LOG.error(dataStoreIdentifier + " is NOT valid DataStore switch marker");
+                    throw new RuntimeException(dataStoreIdentifier + " is NOT valid DataStore switch marker");
+                }
+            }
+        }
+
+        private void putCompositeNodeData(InstanceIdentifier entryKey, CompositeNode entryData,
+                String dataStoreIdentifier) {
+            this.putData(entryKey, entryData, dataStoreIdentifier);
+
+            for (Node<?> child : entryData.getChildren()) {
+                InstanceIdentifier subEntryId = InstanceIdentifier.builder(entryKey).node(child.getNodeType())
+                        .toInstance();
+                if (child instanceof CompositeNode) {
+                    DataSchemaNode subSchema = schemaNodeFor(subEntryId);
+                    CompositeNode compNode = (CompositeNode) child;
+                    InstanceIdentifier instanceId = null;
+
+                    if (subSchema instanceof ListSchemaNode) {
+                        ListSchemaNode listSubSchema = (ListSchemaNode) subSchema;
+                        Map<QName, Object> mapOfSubValues = this.getValuesFromListSchema(listSubSchema,
+                                (CompositeNode) child);
+                        if (mapOfSubValues != null) {
+                            instanceId = InstanceIdentifier.builder(entryKey)
+                                    .nodeWithKey(listSubSchema.getQName(), mapOfSubValues).toInstance();
+                        }
+                    } else if (subSchema instanceof ContainerSchemaNode) {
+                        ContainerSchemaNode containerSchema = (ContainerSchemaNode) subSchema;
+                        instanceId = InstanceIdentifier.builder(entryKey).node(subSchema.getQName()).toInstance();
+                    }
+                    if (instanceId != null) {
+                        this.putCompositeNodeData(instanceId, compNode, dataStoreIdentifier);
+                    }
+                }
+            }
+        }
+
+        private Map<QName, Object> getValuesFromListSchema(ListSchemaNode listSchema, CompositeNode entryData) {
+            List<QName> keyDef = listSchema.getKeyDefinition();
+            if (keyDef != null && !keyDef.isEmpty()) {
+                Map<QName, Object> map = new HashMap<QName, Object>();
+                for (QName key : keyDef) {
+                    List<Node<?>> data = entryData.get(key);
+                    if (data != null && !data.isEmpty()) {
+                        for (Node<?> nodeData : data) {
+                            if (nodeData instanceof SimpleNode<?>) {
+                                map.put(key, data.get(0).getValue());
+                            }
+                        }
+                    }
+                }
+                return map;
+            }
+            return null;
+        }
+    }
 }
index 28d5ae914fc686a8cd41032755b77db529f9a85b..22319abb17df7d1dec301105a59c50fad2cb1164 100644 (file)
@@ -19,6 +19,7 @@ import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener
 import org.opendaylight.controller.md.sal.common.impl.routing.RoutingUtils;
 import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration;
 import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration;
+import org.opendaylight.controller.sal.core.api.RoutedRpcDefaultImplementation;
 import org.opendaylight.controller.sal.core.api.RpcImplementation;
 import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
 import org.opendaylight.controller.sal.core.api.RpcRoutingContext;
@@ -44,7 +45,7 @@ import org.slf4j.LoggerFactory;
 import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableSet;
 
-public class SchemaAwareRpcBroker implements RpcRouter, Identifiable<String> {
+public class SchemaAwareRpcBroker implements RpcRouter, Identifiable<String>, RoutedRpcDefaultImplementation {
 
     private static final Logger LOG = LoggerFactory.getLogger(SchemaAwareRpcBroker.class);
 
@@ -58,6 +59,7 @@ public class SchemaAwareRpcBroker implements RpcRouter, Identifiable<String> {
     private final ConcurrentMap<QName, RpcImplementation> implementations = new ConcurrentHashMap<>();
     private RpcImplementation defaultImplementation;
     private SchemaContextProvider schemaProvider;
+    private RoutedRpcDefaultImplementation defaultDelegate;
 
     public SchemaAwareRpcBroker(String identifier, SchemaContextProvider schemaProvider) {
         super();
@@ -81,7 +83,16 @@ public class SchemaAwareRpcBroker implements RpcRouter, Identifiable<String> {
         this.schemaProvider = schemaProvider;
     }
 
+  public RoutedRpcDefaultImplementation getRoutedRpcDefaultDelegate() {
+    return defaultDelegate;
+  }
+
     @Override
+  public void setRoutedRpcDefaultDelegate(RoutedRpcDefaultImplementation defaultDelegate) {
+    this.defaultDelegate = defaultDelegate;
+  }
+
+  @Override
     public RoutedRpcRegistration addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) {
         checkArgument(rpcType != null, "RPC Type should not be null");
         checkArgument(implementation != null, "RPC Implementatoin should not be null");
@@ -221,6 +232,12 @@ public class SchemaAwareRpcBroker implements RpcRouter, Identifiable<String> {
         return ret;
     }
 
+    @Override
+    public RpcResult<CompositeNode> invokeRpc(QName rpc, InstanceIdentifier identifier, CompositeNode input) {
+      checkState(defaultDelegate != null);
+      return defaultDelegate.invokeRpc(rpc, identifier, input);
+    }
+
     private static abstract class RoutingStrategy implements Identifiable<QName> {
 
         private final QName identifier;
@@ -304,6 +321,7 @@ public class SchemaAwareRpcBroker implements RpcRouter, Identifiable<String> {
             SimpleNode<?> routeContainer = inputContainer.getFirstSimpleByName(strategy.getLeaf());
             checkArgument(routeContainer != null, "Leaf %s must be set with value", strategy.getLeaf());
             Object route = routeContainer.getValue();
+            checkArgument(route instanceof InstanceIdentifier);
             RpcImplementation potential = null;
             if (route != null) {
                 RoutedRpcRegImpl potentialReg = implementations.get(route);
@@ -312,7 +330,7 @@ public class SchemaAwareRpcBroker implements RpcRouter, Identifiable<String> {
                 }
             }
             if (potential == null) {
-                potential = defaultDelegate;
+                return router.invokeRpc(rpc, (InstanceIdentifier) route, input);
             }
             checkState(potential != null, "No implementation is available for rpc:%s path:%s", rpc, route);
             return potential.invokeRpc(rpc, input);
index e218a957826f110bd36d3acb3fe059fc69b5092a..40842c004a2779ede0d231b2fef122920bc4ebc9 100644 (file)
@@ -9,11 +9,7 @@
 package org.opendaylight.controller.sal.dom.broker.osgi;
 
 import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
-import org.opendaylight.controller.sal.core.api.Broker;
-import org.opendaylight.controller.sal.core.api.RpcImplementation;
-import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
-import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
-import org.opendaylight.controller.sal.core.api.RpcRoutingContext;
+import org.opendaylight.controller.sal.core.api.*;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.RpcResult;
@@ -45,7 +41,12 @@ public class RpcProvisionRegistryProxy extends AbstractBrokerServiceProxy<RpcPro
         return getDelegate().addRoutedRpcImplementation(rpcType, implementation);
     }
 
-    @Override
+  @Override
+  public void setRoutedRpcDefaultDelegate(RoutedRpcDefaultImplementation defaultImplementation) {
+    getDelegate().setRoutedRpcDefaultDelegate(defaultImplementation);
+  }
+
+  @Override
     public <L extends RouteChangeListener<RpcRoutingContext, InstanceIdentifier>> ListenerRegistration<L> registerRouteChangeListener(L listener) {
         return getDelegate().registerRouteChangeListener(listener);
     }
index b060ca42d0bca2423cc1af699973706162805f17..289afbbce31c7dd94e827a206d193251103bdcb3 100644 (file)
@@ -5,9 +5,7 @@
         <artifactId>sal-parent</artifactId>
         <version>1.1-SNAPSHOT</version>
     </parent>
-    <properties>
-        <netconf.version>0.2.4-SNAPSHOT</netconf.version>
-    </properties>
+
     <artifactId>sal-netconf-connector</artifactId>
     <scm>
         <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
             <plugin>
                 <groupId>org.opendaylight.yangtools</groupId>
                 <artifactId>yang-maven-plugin</artifactId>
-                <version>${yangtools.version}</version>
                 <executions>
                     <execution>
                         <goals>
                     <dependency>
                         <groupId>org.opendaylight.controller</groupId>
                         <artifactId>yang-jmx-generator-plugin</artifactId>
-                        <version>0.2.4-SNAPSHOT</version>
+                        <version>${config.version}</version>
                     </dependency>
                     <dependency>
                         <groupId>org.opendaylight.yangtools</groupId>
                         <artifactId>maven-sal-api-gen-plugin</artifactId>
-                       <version>${yangtools.version}</version>
+                        <version>${yangtools.version}</version>
                         <type>jar</type>
                     </dependency>
                 </dependencies>
index d4f5d43e5ed0ee077782122b124797a811bb8e42..b0424f945b72660e9dc8190fab910a93dd91eec9 100644 (file)
@@ -30,7 +30,6 @@
             <plugin>
                 <groupId>org.opendaylight.yangtools</groupId>
                 <artifactId>yang-maven-plugin</artifactId>
-                <version>${yangtools.version}</version>
                 <executions>
                     <execution>
                         <id>sal-remote</id>
index 95bb62f93b331257413f2273bcba32ce22fdc7e9..d874381ab374eb2d32a10e09bf959dc810080c0d 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.controller.config.yang.md.sal.remote.rpc;
 
 import org.opendaylight.controller.sal.connector.remoterpc.*;
 import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
 import org.osgi.framework.BundleContext;
 
 /**
@@ -46,17 +47,18 @@ public final class ZeroMQServerModule extends org.opendaylight.controller.config
         
         ClientImpl clientImpl = new ClientImpl();
 
-        RoutingTableProvider provider = new RoutingTableProvider(bundleContext,serverImpl);
+    RoutingTableProvider provider = new RoutingTableProvider(bundleContext);//,serverImpl);
 
-        RemoteRpcProvider facade = new RemoteRpcProvider(serverImpl, clientImpl);
-        
-        facade.setRoutingTableProvider(provider );
-        
-        broker.registerProvider(facade, bundleContext);
-        return facade;
-    }
 
-    public void setBundleContext(BundleContext bundleContext) {
-        this.bundleContext = bundleContext;
-    }
+    facade.setRoutingTableProvider(provider );
+    facade.setContext(bundleContext);
+    facade.setRpcProvisionRegistry((RpcProvisionRegistry) broker);
+
+    broker.registerProvider(facade, bundleContext);
+    return facade;
+  }
+
+  public void setBundleContext(BundleContext bundleContext) {
+    this.bundleContext = bundleContext;
+  }
 }
index 291fe0b8e73a5a52e65f1d6e9be4fcca31290a50..30e11c0806731c24ab151dd7cf585408916fd233 100644 (file)
@@ -12,6 +12,8 @@ import org.opendaylight.controller.sal.common.util.RpcErrors;
 import org.opendaylight.controller.sal.common.util.Rpcs;
 import org.opendaylight.controller.sal.connector.api.RpcRouter;
 import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException;
+import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException;
 import org.opendaylight.controller.sal.connector.remoterpc.dto.Message;
 import org.opendaylight.controller.sal.connector.remoterpc.dto.RouteIdentifierImpl;
 import org.opendaylight.controller.sal.connector.remoterpc.util.XmlUtils;
@@ -20,14 +22,13 @@ import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.RpcError;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.zeromq.ZMQ;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
-import java.util.Set;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.FutureTask;
@@ -66,12 +67,6 @@ public class ClientImpl implements RemoteRpcClient {
     this.routingTableProvider = routingTableProvider;
   }
 
- @Override
-  public Set<QName> getSupportedRpcs(){
-    //TODO: Find the entries from routing table
-    return Collections.emptySet();
-  }
-
   @Override
   public void start() {/*NOOPS*/}
 
@@ -97,14 +92,40 @@ public class ClientImpl implements RemoteRpcClient {
    * @param input payload for the remote service
    * @return
    */
-  @Override
   public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input) {
+    RouteIdentifierImpl routeId = new RouteIdentifierImpl();
+    routeId.setType(rpc);
+
+    String address = lookupRemoteAddressForGlobalRpc(routeId);
+    return sendMessage(input, routeId, address);
+  }
+
+  /**
+   * Finds remote server that can execute this routed rpc and sends a message to it
+   * requesting execution.
+   * The call blocks until a response from remote server is received. Its upto
+   * the client of this API to implement a timeout functionality.
+   *
+   * @param rpc
+   *          rpc to be called
+   * @param identifier
+   *          instance identifier on which rpc is to be executed
+   * @param input
+   *          payload
+   * @return
+   */
+  public RpcResult<CompositeNode> invokeRpc(QName rpc, InstanceIdentifier identifier, CompositeNode input) {
 
     RouteIdentifierImpl routeId = new RouteIdentifierImpl();
     routeId.setType(rpc);
+    routeId.setRoute(identifier);
+
+    String address = lookupRemoteAddressForRpc(routeId);
 
-    String address = lookupRemoteAddress(routeId);
+    return sendMessage(input, routeId, address);
+  }
 
+  private RpcResult<CompositeNode> sendMessage(CompositeNode input, RouteIdentifierImpl routeId, String address) {
     Message request = new Message.MessageBuilder()
         .type(Message.MessageType.REQUEST)
         .sender(Context.getInstance().getLocalUri())
@@ -128,7 +149,6 @@ public class ClientImpl implements RemoteRpcClient {
       collectErrors(e, errors);
       return Rpcs.getRpcResult(false, null, errors);
     }
-
   }
 
   /**
@@ -136,19 +156,36 @@ public class ClientImpl implements RemoteRpcClient {
    * @param  routeId route identifier
    * @return         remote network address
    */
-  private String lookupRemoteAddress(RpcRouter.RouteIdentifier routeId){
+  private String lookupRemoteAddressForGlobalRpc(RpcRouter.RouteIdentifier routeId){
     checkNotNull(routeId, "route must not be null");
 
-    Optional<RoutingTable<String, String>> routingTable = routingTableProvider.getRoutingTable();
+    Optional<RoutingTable<RpcRouter.RouteIdentifier, String>> routingTable = routingTableProvider.getRoutingTable();
     checkNotNull(routingTable.isPresent(), "Routing table is null");
 
-    Set<String> addresses = routingTable.get().getRoutes(routeId.toString());
-    checkNotNull(addresses, "Address not found for route [%s]", routeId);
-    checkState(addresses.size() == 1,
-        "Multiple remote addresses found for route [%s], \nonly 1 expected", routeId); //its a global service.
+    String address = null;
+    try {
+      address = routingTable.get().getGlobalRoute(routeId);
+    } catch (RoutingTableException|SystemException e) {
+      _logger.error("Exception caught while looking up remote address " + e);
+    }
+    checkState(address != null, "Address not found for route [%s]", routeId);
+
+    return address;
+  }
+
+  /**
+   * Find address for the given route identifier in routing table
+   * @param  routeId route identifier
+   * @return         remote network address
+   */
+  private String lookupRemoteAddressForRpc(RpcRouter.RouteIdentifier routeId){
+    checkNotNull(routeId, "route must not be null");
+
+    Optional<RoutingTable<RpcRouter.RouteIdentifier, String>> routingTable = routingTableProvider.getRoutingTable();
+    checkNotNull(routingTable.isPresent(), "Routing table is null");
 
-    String address = addresses.iterator().next();
-    checkNotNull(address, "Address not found for route [%s]", routeId);
+    String address = routingTable.get().getLastAddedRoute(routeId);
+    checkState(address != null, "Address not found for route [%s]", routeId);
 
     return address;
   }
index 1f78a6771a0b6deb1f4d208db11ecb2275a04a73..a564a0ad045a533818135b2921c173e684a603b1 100644 (file)
@@ -9,9 +9,9 @@
 package org.opendaylight.controller.sal.connector.remoterpc;
 
 import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.sal.core.api.RoutedRpcDefaultImplementation;
 
-public interface RemoteRpcClient extends RpcImplementation,AutoCloseable{
-
+public interface RemoteRpcClient extends AutoCloseable{
 
     void setRoutingTableProvider(RoutingTableProvider provider);
     
index bf205fc38d54a57ebc2ac351a3436f1d0215dbd9..639e31ddc3ec0e8380b5108efbe8f4afa92ec513 100644 (file)
 
 package org.opendaylight.controller.sal.connector.remoterpc;
 
+import com.google.common.base.Optional;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
+import org.opendaylight.controller.sal.connector.api.RpcRouter;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException;
+import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.RouteIdentifierImpl;
 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
 import org.opendaylight.controller.sal.core.api.Provider;
+import org.opendaylight.controller.sal.core.api.RoutedRpcDefaultImplementation;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
+import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
+import org.opendaylight.controller.sal.core.api.RpcRoutingContext;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.osgi.framework.BundleContext;
+import org.osgi.util.tracker.ServiceTracker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
 
-public class RemoteRpcProvider implements 
-    RemoteRpcServer,
-    RemoteRpcClient,
+import static com.google.common.base.Preconditions.checkNotNull;
+
+public class RemoteRpcProvider implements
+    RpcImplementation,
+    RoutedRpcDefaultImplementation,
+    AutoCloseable,
     Provider {
 
-    private final ServerImpl server;
-    private final ClientImpl client;
-    private RoutingTableProvider provider;
+  private Logger _logger = LoggerFactory.getLogger(RemoteRpcProvider.class);
 
-    @Override
-    public void setRoutingTableProvider(RoutingTableProvider provider) {
-        this.provider = provider;
-        server.setRoutingTableProvider(provider);
-        client.setRoutingTableProvider(provider);
+  private final ServerImpl server;
+  private final ClientImpl client;
+  private RoutingTableProvider routingTableProvider;
+  private final RpcListener listener = new RpcListener();
+  private final RoutedRpcListener routeChangeListener = new RoutedRpcListener();
+  private ProviderSession brokerSession;
+  private RpcProvisionRegistry rpcProvisionRegistry;
+  private BundleContext context;
+  private ServiceTracker clusterTracker;
+
+  public RemoteRpcProvider(ServerImpl server, ClientImpl client) {
+    this.server = server;
+    this.client = client;
+  }
+
+  public void setRoutingTableProvider(RoutingTableProvider provider) {
+    this.routingTableProvider = provider;
+    client.setRoutingTableProvider(provider);
+  }
+
+  public void setContext(BundleContext context){
+    this.context = context;
+  }
+
+  public void setRpcProvisionRegistry(RpcProvisionRegistry rpcProvisionRegistry){
+    this.rpcProvisionRegistry = rpcProvisionRegistry;
+  }
+
+  @Override
+  public void onSessionInitiated(ProviderSession session) {
+    brokerSession = session;
+    server.setBrokerSession(session);
+    start();
+  }
+
+  @Override
+  public Set<QName> getSupportedRpcs() {
+    //TODO: Ask Tony if we need to get this from routing table
+    return Collections.emptySet();
+  }
+
+  @Override
+  public Collection<ProviderFunctionality> getProviderFunctionality() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input) {
+    return client.invokeRpc(rpc, input);
+  }
+
+  @Override
+  public RpcResult<CompositeNode> invokeRpc(QName rpc, InstanceIdentifier identifier, CompositeNode input) {
+    return client.invokeRpc(rpc, identifier, input);
+  }
+
+  public void start() {
+    server.start();
+    client.start();
+    brokerSession.addRpcRegistrationListener(listener);
+    rpcProvisionRegistry.setRoutedRpcDefaultDelegate(this);
+    rpcProvisionRegistry.registerRouteChangeListener(routeChangeListener);
+
+    announceSupportedRpcs();
+    announceSupportedRoutedRpcs();
+  }
+
+  @Override
+  public void close() throws Exception {
+    unregisterSupportedRpcs();
+    unregisterSupportedRoutedRpcs();
+    server.close();
+    client.close();
+  }
+
+  public void stop() {
+    server.stop();
+    client.stop();
+  }
+
+  /**
+   * Add all the locally registered RPCs in the clustered routing table
+   */
+  private void announceSupportedRpcs(){
+    Set<QName> currentlySupported = brokerSession.getSupportedRpcs();
+    for (QName rpc : currentlySupported) {
+      listener.onRpcImplementationAdded(rpc);
     }
-    
-    @Override
-    public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input) {
-        return client.invokeRpc(rpc, input);
+  }
+
+  /**
+   * Add all the locally registered Routed RPCs in the clustered routing table
+   */
+  private void announceSupportedRoutedRpcs(){
+
+    //TODO: announce all routed RPCs as well
+
+  }
+
+  /**
+   * Un-Register all the supported RPCs from clustered routing table
+   */
+  private void unregisterSupportedRpcs(){
+    Set<QName> currentlySupported = brokerSession.getSupportedRpcs();
+    //TODO: remove all routed RPCs as well
+    for (QName rpc : currentlySupported) {
+      listener.onRpcImplementationRemoved(rpc);
     }
-    
+  }
+
+  /**
+   * Un-Register all the locally supported Routed RPCs from clustered routing table
+   */
+  private void unregisterSupportedRoutedRpcs(){
+
+    //TODO: remove all routed RPCs as well
+
+  }
+
+  private RoutingTable<RpcRouter.RouteIdentifier, String> getRoutingTable(){
+    Optional<RoutingTable<RpcRouter.RouteIdentifier, String>> routingTable =
+        routingTableProvider.getRoutingTable();
+
+    checkNotNull(routingTable.isPresent(), "Routing table is null");
+
+    return routingTable.get();
+  }
+
+  /**
+   * Listener for rpc registrations in broker
+   */
+  private class RpcListener implements RpcRegistrationListener {
+
     @Override
-    public Set<QName> getSupportedRpcs() {
-        return client.getSupportedRpcs();
-    }
-    
-    
-    public RemoteRpcProvider(ServerImpl server, ClientImpl client) {
-        this.server = server;
-        this.client = client;
-    }
-    
-    public void setBrokerSession(ProviderSession session) {
-        server.setBrokerSession(session);
-    }
-//    public void setServerPool(ExecutorService serverPool) {
-//        server.setServerPool(serverPool);
-//    }
-    public void start() {
-        //when listener was being invoked and addRPCImplementation was being
-        //called the client was null.
-        server.setClient(client);
-        server.start();
-        client.start();
+    public void onRpcImplementationAdded(QName rpc) {
+
+      _logger.debug("Adding registration for [{}]", rpc);
+      RouteIdentifierImpl routeId = new RouteIdentifierImpl();
+      routeId.setType(rpc);
 
+      RoutingTable<RpcRouter.RouteIdentifier, String> routingTable = getRoutingTable();
 
+      try {
+        routingTable.addGlobalRoute(routeId, server.getServerAddress());
+        _logger.debug("Route added [{}-{}]", routeId, server.getServerAddress());
+
+      } catch (RoutingTableException | SystemException e) {
+        //TODO: This can be thrown when route already exists in the table. Broker
+        //needs to handle this.
+        _logger.error("Unhandled exception while adding global route to routing table [{}]", e);
+
+      }
     }
 
-    
     @Override
-    public Collection<ProviderFunctionality> getProviderFunctionality() {
-        // TODO Auto-generated method stub
-        return null;
+    public void onRpcImplementationRemoved(QName rpc) {
+
+      _logger.debug("Removing registration for [{}]", rpc);
+      RouteIdentifierImpl routeId = new RouteIdentifierImpl();
+      routeId.setType(rpc);
+
+      RoutingTable<RpcRouter.RouteIdentifier, String> routingTable = getRoutingTable();
+
+      try {
+        routingTable.removeGlobalRoute(routeId);
+      } catch (RoutingTableException | SystemException e) {
+        _logger.error("Route delete failed {}", e);
+      }
     }
-    
-    
+  }
+
+  /**
+   * Listener for Routed Rpc registrations in broker
+   */
+  private class RoutedRpcListener
+      implements RouteChangeListener<RpcRoutingContext, InstanceIdentifier> {
+
+    /**
+     *
+     * @param routeChange
+     */
     @Override
-    public void onSessionInitiated(ProviderSession session) {
-        server.setBrokerSession(session);
-        start();
+    public void onRouteChange(RouteChange<RpcRoutingContext, InstanceIdentifier> routeChange) {
+      Map<RpcRoutingContext, Set<InstanceIdentifier>> announcements = routeChange.getAnnouncements();
+      announce(getRouteIdentifiers(announcements));
+
+      Map<RpcRoutingContext, Set<InstanceIdentifier>> removals = routeChange.getRemovals();
+      remove(getRouteIdentifiers(removals));
+    }
+
+    /**
+     *
+     * @param announcements
+     */
+    private void announce(Set<RpcRouter.RouteIdentifier> announcements) {
+      _logger.debug("Announcing [{}]", announcements);
+      RoutingTable<RpcRouter.RouteIdentifier, String> routingTable = getRoutingTable();
+      try {
+        routingTable.addRoutes(announcements, server.getServerAddress());
+      } catch (RoutingTableException | SystemException e) {
+        _logger.error("Route announcement failed {}", e);
+      }
     }
-    
-    
-    public void close() throws Exception {
-        server.close();
-        client.close();
+
+    /**
+     *
+     * @param removals
+     */
+    private void remove(Set<RpcRouter.RouteIdentifier> removals){
+      _logger.debug("Removing [{}]", removals);
+      RoutingTable<RpcRouter.RouteIdentifier, String> routingTable = getRoutingTable();
+      try {
+        routingTable.removeRoutes(removals, server.getServerAddress());
+      } catch (RoutingTableException | SystemException e) {
+        _logger.error("Route removal failed {}", e);
+      }
     }
 
-    @Override
-    public void stop() {
-        server.stop();
-        client.stop();
+    /**
+     *
+     * @param changes
+     * @return
+     */
+    private Set<RpcRouter.RouteIdentifier> getRouteIdentifiers(Map<RpcRoutingContext, Set<InstanceIdentifier>> changes) {
+      RouteIdentifierImpl routeId = null;
+      Set<RpcRouter.RouteIdentifier> routeIdSet = new HashSet<RpcRouter.RouteIdentifier>();
+
+      for (RpcRoutingContext context : changes.keySet()){
+        routeId = new RouteIdentifierImpl();
+        routeId.setType(context.getRpc());
+        routeId.setContext(context.getContext());
+
+        for (InstanceIdentifier instanceId : changes.get(context)){
+          routeId.setRoute(instanceId);
+          routeIdSet.add(routeId);
+        }
+      }
+      return routeIdSet;
     }
+
+
+
+  }
+
 }
index f62c26e0fdaad757112f4e80e860dcd97a464552..71bab288e6ce3c38c555a036cf3a6b05c35af4de 100644 (file)
@@ -9,8 +9,10 @@
 package org.opendaylight.controller.sal.connector.remoterpc;
 
 import com.google.common.base.Optional;
+import org.opendaylight.controller.sal.connector.api.RpcRouter;
 import org.opendaylight.controller.sal.connector.remoterpc.api.RouteChangeListener;
 import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
+import org.opendaylight.controller.sal.connector.remoterpc.dto.RouteIdentifierImpl;
 import org.opendaylight.controller.sal.connector.remoterpc.impl.RoutingTableImpl;
 import org.osgi.framework.BundleContext;
 import org.osgi.util.tracker.ServiceTracker;
@@ -22,26 +24,26 @@ public class RoutingTableProvider implements AutoCloseable {
 
     private RoutingTableImpl routingTableImpl = null;
 
-    final private RouteChangeListener routeChangeListener;
+    //final private RouteChangeListener routeChangeListener;
     
     
-    public RoutingTableProvider(BundleContext ctx,RouteChangeListener rcl) {
+    public RoutingTableProvider(BundleContext ctx){//,RouteChangeListener rcl) {
         @SuppressWarnings("rawtypes")
         ServiceTracker<RoutingTable, RoutingTable> rawTracker = new ServiceTracker<>(ctx, RoutingTable.class, null);
         tracker = rawTracker;
         tracker.open();
 
-        routeChangeListener = rcl;
+        //routeChangeListener = rcl;
     }
     
-    public Optional<RoutingTable<String, String>> getRoutingTable() {
+    public Optional<RoutingTable<RpcRouter.RouteIdentifier, String>> getRoutingTable() {
         @SuppressWarnings("unchecked")
-        RoutingTable<String,String> tracked = tracker.getService();
+        RoutingTable<RpcRouter.RouteIdentifier,String> tracked = tracker.getService();
 
         if(tracked instanceof RoutingTableImpl){
             if(routingTableImpl != tracked){
              routingTableImpl= (RoutingTableImpl)tracked;
-             routingTableImpl.setRouteChangeListener(routeChangeListener);
+             //routingTableImpl.setRouteChangeListener(routeChangeListener);
             }
         }
 
index 5c14dd0c453ce8365e528506d743699edf418f3a..722ca0687904f2c7f2e5c42572fc2d16c762936b 100644 (file)
@@ -18,6 +18,7 @@ import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableExcep
 import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException;
 import org.opendaylight.controller.sal.connector.remoterpc.dto.RouteIdentifierImpl;
 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
 import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
 import org.opendaylight.controller.sal.core.api.RpcRoutingContext;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -43,10 +44,9 @@ import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
 
 /**
- * ZeroMq based implementation of RpcRouter. It implements RouteChangeListener of RoutingTable
- * so that it gets route change notifications from routing table.
+ * ZeroMq based implementation of RpcRouter.
  */
-public class ServerImpl implements RemoteRpcServer, RouteChangeListener<String, String> {
+public class ServerImpl implements RemoteRpcServer {
 
   private Logger _logger = LoggerFactory.getLogger(ServerImpl.class);
 
@@ -57,8 +57,6 @@ public class ServerImpl implements RemoteRpcServer, RouteChangeListener<String,
   private ProviderSession brokerSession;
   private ZMQ.Context context;
 
-  private final RpcListener listener = new RpcListener();
-
   private final String HANDLER_INPROC_ADDRESS = "inproc://rpc-request-handler";
   private final int HANDLER_WORKER_COUNT = 2;
   private final int HWM = 200;//high water mark on sockets
@@ -67,10 +65,6 @@ public class ServerImpl implements RemoteRpcServer, RouteChangeListener<String,
   private String serverAddress;
   private int port;
 
-  private ClientImpl client;
-
-  private  RoutingTableProvider routingTableProvider;
-
   public static enum State {
     STARTING, STARTED, STOPPED;
   }
@@ -79,22 +73,6 @@ public class ServerImpl implements RemoteRpcServer, RouteChangeListener<String,
     this.port = port;
   }
 
-  public RoutingTableProvider getRoutingTableProvider() {
-    return routingTableProvider;
-  }
-
-  public void setRoutingTableProvider(RoutingTableProvider routingTableProvider) {
-    this.routingTableProvider = routingTableProvider;
-  }
-
-  public ClientImpl getClient(){
-    return this.client;
-  }
-
-  public void setClient(ClientImpl client) {
-    this.client = client;
-  }
-
   public State getStatus() {
     return this.status;
   }
@@ -157,11 +135,6 @@ public class ServerImpl implements RemoteRpcServer, RouteChangeListener<String,
     remoteServices = new HashSet<QName>();//
     serverPool = Executors.newSingleThreadExecutor();//main server thread
     serverPool.execute(receive()); // Start listening rpc requests
-    brokerSession.addRpcRegistrationListener(listener);
-
-    announceLocalRpcs();
-
-    registerRemoteRpcs();
 
     status = State.STARTED;
     _logger.info("Remote RPC Server started [{}]", getServerAddress());
@@ -179,8 +152,6 @@ public class ServerImpl implements RemoteRpcServer, RouteChangeListener<String,
 
     if (State.STOPPED == this.getStatus()) return; //do nothing
 
-    unregisterLocalRpcs();
-
     if (serverPool != null)
       serverPool.shutdown();
 
@@ -192,7 +163,7 @@ public class ServerImpl implements RemoteRpcServer, RouteChangeListener<String,
 
   /**
    * Closes ZMQ Context. It tries to gracefully terminate the context. If
-   * termination takes more than a second, its forcefully shutdown.
+   * termination takes more than 5 seconds, its forcefully shutdown.
    */
   private void closeZmqContext() {
     ExecutorService exec = Executors.newSingleThreadExecutor();
@@ -269,81 +240,6 @@ public class ServerImpl implements RemoteRpcServer, RouteChangeListener<String,
     };
   }
 
-  /**
-   * Register the remote RPCs from the routing table into broker
-   */
-  private void registerRemoteRpcs(){
-    Optional<RoutingTable<String, String>> routingTableOptional = routingTableProvider.getRoutingTable();
-
-    Preconditions.checkState(routingTableOptional.isPresent(), "Routing table is absent");
-
-    Set<Map.Entry> remoteRoutes =
-            routingTableProvider.getRoutingTable().get().getAllRoutes();
-
-    //filter out all entries that contains local address
-    //we dont want to register local RPCs as remote
-    Predicate<Map.Entry> notLocalAddressFilter = new Predicate<Map.Entry>(){
-      public boolean apply(Map.Entry remoteRoute){
-        return !getServerAddress().equalsIgnoreCase((String)remoteRoute.getValue());
-      }
-    };
-
-    //filter the entries created by current node
-    Set<Map.Entry> filteredRemoteRoutes = Sets.filter(remoteRoutes, notLocalAddressFilter);
-
-    for (Map.Entry route : filteredRemoteRoutes){
-      onRouteUpdated((String) route.getKey(), "");//value is not needed by broker
-    }
-  }
-
-  /**
-   * Un-Register the local RPCs from the routing table
-   */
-  private void unregisterLocalRpcs(){
-    Set<QName> currentlySupported = brokerSession.getSupportedRpcs();
-    for (QName rpc : currentlySupported) {
-      listener.onRpcImplementationRemoved(rpc);
-    }
-  }
-
-  /**
-   * Publish all the locally registered RPCs in the routing table
-   */
-  private void announceLocalRpcs(){
-    Set<QName> currentlySupported = brokerSession.getSupportedRpcs();
-    for (QName rpc : currentlySupported) {
-      listener.onRpcImplementationAdded(rpc);
-    }
-  }
-
-  /**
-   * @param key
-   * @param value
-   */
-  @Override
-  public void onRouteUpdated(String key, String value) {
-    RouteIdentifierImpl rId = new RouteIdentifierImpl();
-    try {
-      _logger.debug("Updating key/value {}-{}", key, value);
-      brokerSession.addRpcImplementation(
-          (QName) rId.fromString(key).getType(), client);
-
-      //TODO: Check with Tony for routed rpc
-      //brokerSession.addRoutedRpcImplementation((QName) rId.fromString(key).getRoute(), client);
-    } catch (Exception e) {
-      _logger.info("Route update failed {}", e);
-    }
-  }
-
-  /**
-   * @param key
-   */
-  @Override
-  public void onRouteDeleted(String key) {
-    //TODO: Broker session needs to be updated to support this
-    throw new UnsupportedOperationException();
-  }
-
   /**
    * Finds IPv4 address of the local VM
    * TODO: This method is non-deterministic. There may be more than one IPv4 address. Cant say which
@@ -381,74 +277,4 @@ public class ServerImpl implements RemoteRpcServer, RouteChangeListener<String,
     return null;
   }
 
-  /**
-   * Listener for rpc registrations
-   */
-  private class RpcListener implements RpcRegistrationListener {
-
-    @Override
-    public void onRpcImplementationAdded(QName name) {
-
-      //if the service name exists in the set, this notice
-      //has bounced back from the broker. It should be ignored
-      if (remoteServices.contains(name))
-        return;
-
-      _logger.debug("Adding registration for [{}]", name);
-      RouteIdentifierImpl routeId = new RouteIdentifierImpl();
-      routeId.setType(name);
-
-      RoutingTable<String, String> routingTable = getRoutingTable();
-
-      try {
-        routingTable.addGlobalRoute(routeId.toString(), getServerAddress());
-        _logger.debug("Route added [{}-{}]", name, getServerAddress());
-
-      } catch (RoutingTableException | SystemException e) {
-        //TODO: This can be thrown when route already exists in the table. Broker
-        //needs to handle this.
-        _logger.error("Unhandled exception while adding global route to routing table [{}]", e);
-
-      }
-    }
-
-    @Override
-    public void onRpcImplementationRemoved(QName name) {
-
-      _logger.debug("Removing registration for [{}]", name);
-      RouteIdentifierImpl routeId = new RouteIdentifierImpl();
-      routeId.setType(name);
-
-      RoutingTable<String, String> routingTable = getRoutingTable();
-
-      try {
-        routingTable.removeGlobalRoute(routeId.toString());
-      } catch (RoutingTableException | SystemException e) {
-        _logger.error("Route delete failed {}", e);
-      }
-    }
-
-    private RoutingTable<String, String> getRoutingTable(){
-      Optional<RoutingTable<String, String>> routingTable =
-          routingTableProvider.getRoutingTable();
-
-      checkNotNull(routingTable.isPresent(), "Routing table is null");
-
-      return routingTable.get();
-    }
-  }
-
-  /*
-   * Listener for Route changes in broker. Broker notifies this listener in the event
-   * of any change (add/delete). Listener then updates the routing table.
-   */
-  private class BrokerRouteChangeListener
-      implements org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener<RpcRoutingContext, InstanceIdentifier>{
-
-    @Override
-    public void onRouteChange(RouteChange<RpcRoutingContext, InstanceIdentifier> routeChange) {
-
-    }
-  }
-
 }
index 06107a8773a6213f79df91c3a2bd637e085647ff..ec6a1a94b6ecfe2a4d58504f332145ccd5c53184 100644 (file)
@@ -18,8 +18,6 @@ import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 
 public class RouteIdentifierImpl implements RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier>,Serializable {
 
-  transient ObjectMapper mapper = new ObjectMapper();
-
   private QName context;
   private QName type;
   private InstanceIdentifier route;
@@ -50,38 +48,4 @@ public class RouteIdentifierImpl implements RpcRouter.RouteIdentifier<QName, QNa
   public void setRoute(InstanceIdentifier route) {
     this.route = route;
   }
-
-  @Override
-  public String toString() {
-    try {
-      return mapper.writeValueAsString(this);
-    } catch (Throwable e) {
-      //do nothing
-    }
-
-    return super.toString();
-  }
-
-  public RpcRouter.RouteIdentifier fromString(String input)
-      throws Exception {
-
-    JsonNode root = mapper.readTree(input);
-    this.context  = parseQName(root.get("context"));
-    this.type     = parseQName(root.get("type"));
-
-    return this;
-  }
-
-  private QName parseQName(JsonNode node){
-    if (node == null) return null;
-
-    String namespace = (node.get("namespace") != null) ?
-                       node.get("namespace").asText()  : "";
-
-    String localName = (node.get("localName") != null) ?
-                       node.get("localName").asText() : "";
-
-    URI uri = URI.create(namespace);
-    return new QName(uri, localName);
-  }
 }
index d20efe50c154a054e46eb83aaf1b4c3d2520393c..beeb936c97200517fc911276e56a483e182c1b5f 100644 (file)
@@ -26,8 +26,6 @@ module odl-sal-dom-rpc-remote-cfg {
 
     identity remote-zeromq-rpc-server {
         base config:module-type;
-        config:provided-service remote-rpc-server;
-        config:provided-service remote-rpc-client;
         config:java-name-prefix ZeroMQServer;
     }
 
index f63584b7fc4531b11466e1a84f07cbf14b46eae7..c0aae2dfb56590a39ac1e90a5a413b29c2a87cdb 100644 (file)
@@ -13,6 +13,7 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.controller.sal.common.util.Rpcs;
+import org.opendaylight.controller.sal.connector.api.RpcRouter;
 import org.opendaylight.controller.sal.connector.remoterpc.api.RouteChangeListener;
 import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
 import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException;
@@ -43,8 +44,8 @@ public class ClientImplTest {
 
     //mock routing table
     routingTableProvider = mock(RoutingTableProvider.class);
-    RoutingTable<String, String> mockRoutingTable = new MockRoutingTable<String, String>();
-    Optional<RoutingTable<String, String>> optionalRoutingTable = Optional.fromNullable(mockRoutingTable);
+    RoutingTable<RpcRouter.RouteIdentifier, String> mockRoutingTable = new MockRoutingTable<String, String>();
+    Optional<RoutingTable<RpcRouter.RouteIdentifier, String>> optionalRoutingTable = Optional.fromNullable(mockRoutingTable);
     when(routingTableProvider.getRoutingTable()).thenReturn(optionalRoutingTable);
 
     //mock ClientRequestHandler
@@ -81,7 +82,7 @@ public class ClientImplTest {
 
   }
 
-  @Test
+  //@Test
   public void invokeRpc_NormalCall_ShouldReturnSuccess() throws Exception {
 
     when(mockHandler.handle(any(Message.class))).
@@ -94,7 +95,7 @@ public class ClientImplTest {
     Assert.assertNull(result.getResult());
   }
 
-  @Test
+  //@Test
   public void invokeRpc_HandlerThrowsException_ShouldReturnError() throws Exception {
 
     when(mockHandler.handle(any(Message.class))).
index 9c74be93bd7d28e22222cffb8273c2ae5b2505f7..0fe0155bb6a90e48a24e3ce7d3ecaaee37f956f8 100644 (file)
@@ -38,11 +38,26 @@ public class MockRoutingTable<K, V> implements RoutingTable {
 
   }
 
+  @Override
+  public void addRoutes(Set set, Object o) throws RoutingTableException, SystemException {
+    //To change body of implemented methods use File | Settings | File Templates.
+  }
+
+  @Override
+  public void removeRoutes(Set set, Object o) throws RoutingTableException, SystemException {
+    //To change body of implemented methods use File | Settings | File Templates.
+  }
+
   @Override
   public void removeGlobalRoute(Object o) throws RoutingTableException, SystemException {
 
   }
 
+  @Override
+  public Object getGlobalRoute(Object o) throws RoutingTableException, SystemException {
+    return null;  //To change body of implemented methods use File | Settings | File Templates.
+  }
+
   @Override
   public Set getRoutes(Object o) {
     Set<String> routes = new HashSet<String>();
@@ -51,17 +66,17 @@ public class MockRoutingTable<K, V> implements RoutingTable {
   }
 
   @Override
-  public Set<Map.Entry> getAllRoutes() {
-    return Collections.emptySet();
+  public Object getLastAddedRoute(Object o) {
+    return null;  //To change body of implemented methods use File | Settings | File Templates.
   }
 
-  @Override
-  public Object getARoute(Object o) {
-    return null;
-  }
+//  @Override
+//  public Set<Map.Entry> getAllRoutes() {
+//    return Collections.emptySet();
+//  }
 
-  @Override
-  public void registerRouteChangeListener(RouteChangeListener routeChangeListener) {
-
-  }
+//  @Override
+//  public Object getARoute(Object o) {
+//    return null;
+//  }
 }
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/RemoteRpcProviderTest.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/RemoteRpcProviderTest.java
new file mode 100644 (file)
index 0000000..06360aa
--- /dev/null
@@ -0,0 +1,62 @@
+package org.opendaylight.controller.sal.connector.remoterpc;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class RemoteRpcProviderTest {
+  @Before
+  public void setUp() throws Exception {
+
+  }
+
+  @After
+  public void tearDown() throws Exception {
+
+  }
+
+  @Test
+  public void testSetRoutingTableProvider() throws Exception {
+
+  }
+
+  @Test
+  public void testOnSessionInitiated() throws Exception {
+
+  }
+
+  @Test
+  public void testGetSupportedRpcs() throws Exception {
+
+  }
+
+  @Test
+  public void testGetProviderFunctionality() throws Exception {
+
+  }
+
+  @Test
+  public void testInvokeRpc() throws Exception {
+
+  }
+
+  @Test
+  public void testInvokeRoutedRpc() throws Exception {
+
+  }
+
+  @Test
+  public void testStart() throws Exception {
+
+  }
+
+  @Test
+  public void testClose() throws Exception {
+
+  }
+
+  @Test
+  public void testStop() throws Exception {
+
+  }
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/RouteIdentifierImplTest.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/RouteIdentifierImplTest.java
deleted file mode 100644 (file)
index 468d782..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.sal.connector.remoterpc;
-
-import java.net.URI;
-
-import com.fasterxml.jackson.core.JsonParseException;
-import org.junit.Assert;
-import org.junit.Test;
-import org.opendaylight.controller.sal.connector.api.RpcRouter;
-import org.opendaylight.controller.sal.connector.remoterpc.dto.RouteIdentifierImpl;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class RouteIdentifierImplTest {
-
-  Logger _logger = LoggerFactory.getLogger(RouteIdentifierImplTest.class);
-
-  private final URI namespace = URI.create("http://cisco.com/example");
-  private final QName QNAME = new QName(namespace, "heartbeat");
-
-  @Test
-  public void testToString() throws Exception {
-    RouteIdentifierImpl rId = new RouteIdentifierImpl();
-    rId.setType(QNAME);
-
-    _logger.debug(rId.toString());
-
-    Assert.assertTrue(true);
-
-  }
-
-  @Test
-  public void testFromString() throws Exception {
-    RouteIdentifierImpl rId = new RouteIdentifierImpl();
-    rId.setType(QNAME);
-
-    String s = rId.toString();
-    _logger.debug("serialized route: {}", s);
-
-    RpcRouter.RouteIdentifier ref = new RouteIdentifierImpl().fromString(s);
-    _logger.debug("deserialized route: {}", ref);
-
-    Assert.assertTrue(true);
-  }
-
-  @Test(expected = JsonParseException.class)
-  public void testFromInvalidString() throws Exception {
-    String invalidInput = "aklhdgadfa;;;;;;;]]]]=]ag" ;
-    RouteIdentifierImpl rId = new RouteIdentifierImpl();
-    rId.fromString(invalidInput);
-
-    _logger.debug("" + rId);
-    Assert.assertTrue(true);
-  }
-}
index 1b282f6ab5e5ead6d903c387cea22d015afba297..886ff426c7948d4a95d778d0f5717da1f0aa582e 100644 (file)
@@ -11,6 +11,7 @@ package org.opendaylight.controller.sal.connector.remoterpc;
 import com.google.common.base.Optional;
 import junit.framework.Assert;
 import org.junit.*;
+import org.opendaylight.controller.sal.connector.api.RpcRouter;
 import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
 import org.opendaylight.controller.sal.connector.remoterpc.utils.MessagingUtil;
 import org.opendaylight.controller.sal.core.api.Broker;
@@ -66,10 +67,9 @@ public class ServerImplTest {
 
     server = new ServerImpl(port);
     server.setBrokerSession(brokerSession);
-    server.setRoutingTableProvider(routingTableProvider);
 
-    RoutingTable<String, String> mockRoutingTable = new MockRoutingTable<String, String>();
-    Optional<RoutingTable<String, String>> optionalRoutingTable = Optional.fromNullable(mockRoutingTable);
+    RoutingTable<RpcRouter.RouteIdentifier, String> mockRoutingTable = new MockRoutingTable<String, String>();
+    Optional<RoutingTable<RpcRouter.RouteIdentifier, String>> optionalRoutingTable = Optional.fromNullable(mockRoutingTable);
     when(routingTableProvider.getRoutingTable()).thenReturn(optionalRoutingTable);
 
     when(brokerSession.addRpcRegistrationListener(listener)).thenReturn(null);
@@ -94,11 +94,6 @@ public class ServerImplTest {
     Assert.assertEquals(ServerImpl.State.STOPPED, server.getStatus());
   }
 
-  @Test
-  public void getRoutingTableProvider_Call_ShouldReturnRoutingTable() throws Exception {
-    Assert.assertNotNull(server.getRoutingTableProvider());
-  }
-
   @Test
   public void getBrokerSession_Call_ShouldReturnBrokerSession() throws Exception {
     Optional<Broker.ProviderSession> mayBeBroker = server.getBrokerSession();
index dc2fdbf9a05382d19307d6cccb20c918c6c1aafc..a6bbe31684008c00722482b6e4eb2078d60fa4d4 100644 (file)
             </Export-Package>
             <Import-Package>
               com.sun.jersey.spi.container.servlet,
-              org.codehaus.jackson.annotate,
+              !org.codehaus.jackson.annotate,
               javax.ws.rs,
               javax.ws.rs.core,
               javax.xml.bind,
               javax.xml.bind.annotation,
               org.slf4j,
               org.apache.catalina.filters,
-              org.codehaus.jackson.jaxrs,
+              !org.codehaus.jackson.jaxrs,
               org.opendaylight.controller.sample.zeromq.provider,
               org.opendaylight.controller.sample.zeromq.consumer,
               org.opendaylight.controller.sal.utils,
index 6fe56c87edc65ac2399faf8b07c6f0a590d92b2b..416f1941c1f10375fcb27eaf95e83dc65393f5ae 100644 (file)
@@ -8,19 +8,16 @@
 package org.opendaylight.controller.sal.restconf.binding.impl;
 
 import java.net.URL;
-import java.util.concurrent.Future;
+
 import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
 import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext;
 import org.opendaylight.yangtools.restconf.client.api.RestconfClientContextFactory;
 import org.opendaylight.yangtools.restconf.client.api.UnsupportedProtocolException;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.DataRoot;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
 import org.opendaylight.yangtools.yang.model.api.SchemaContextHolder;
 import org.slf4j.Logger;
@@ -35,45 +32,6 @@ public class DataBrokerServiceImpl implements DataBrokerService {
     public DataBrokerServiceImpl(URL baseUrl, BindingIndependentMappingService mappingService, SchemaContextHolder schemaContextHolder) throws UnsupportedProtocolException {
         this.restconfClientContext = restconfClientContextFactory.getRestconfClientContext(baseUrl, mappingService, schemaContextHolder);
     }
-    @Override
-    public <T extends DataRoot> T getData(DataStoreIdentifier store, Class<T> rootType) {
-        return null;
-    }
-
-    @Override
-    public <T extends DataRoot> T getData(DataStoreIdentifier store, T filter) {
-        return null;
-    }
-
-    @Override
-    public <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, Class<T> rootType) {
-        return null;
-    }
-
-    @Override
-    public <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, T filter) {
-        return null;
-    }
-
-    @Override
-    public RpcResult<DataRoot> editCandidateData(DataStoreIdentifier store, DataRoot changeSet) {
-        return null;
-    }
-
-    @Override
-    public Future<RpcResult<Void>> commit(DataStoreIdentifier store) {
-        return null;
-    }
-
-    @Override
-    public DataObject getData(InstanceIdentifier<? extends DataObject> data) {
-        return null;
-    }
-
-    @Override
-    public DataObject getConfigurationData(InstanceIdentifier<?> data) {
-        return null;
-    }
 
     @Override
     public DataModificationTransaction beginTransaction() {
@@ -81,16 +39,6 @@ public class DataBrokerServiceImpl implements DataBrokerService {
         return null;
     }
 
-    @Override
-    public void registerChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener) {
-
-    }
-
-    @Override
-    public void unregisterChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener) {
-
-    }
-
     @Override
     public DataObject readConfigurationData(InstanceIdentifier<? extends DataObject> path) {
         //TODO implementation using restconf-client
@@ -109,9 +57,4 @@ public class DataBrokerServiceImpl implements DataBrokerService {
         //TODO implementation using restconf-client
         return null;
     }
-
-
-
-
-
 }
@@ -5,8 +5,12 @@
  * 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.sample.toaster.provider;
+package org.opendaylight.controller.sal.restconf.broker.client;
 
-public class ToasterActivator {
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
+
+public interface SalRemoteClient extends AutoCloseable {
+
+    ConsumerContext registerConsumer();
 
 }
diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/client/SalRemoteClientDeployer.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/client/SalRemoteClientDeployer.java
new file mode 100644 (file)
index 0000000..a1bb81b
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.broker.client;
+
+import java.net.URL;
+
+public class SalRemoteClientDeployer {
+
+    public static SalRemoteClient createSalRemoteClient(final URL url) {
+        return new SalRemoteClientImpl(url);
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/client/SalRemoteClientImpl.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/client/SalRemoteClientImpl.java
new file mode 100644 (file)
index 0000000..ec62568
--- /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.sal.restconf.broker.client;
+
+import java.net.URL;
+
+import javassist.ClassPool;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
+import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer;
+import org.opendaylight.controller.sal.restconf.broker.SalRemoteServiceBroker;
+import org.opendaylight.yangtools.restconf.client.RestconfClientFactory;
+import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext;
+import org.opendaylight.yangtools.restconf.client.api.UnsupportedProtocolException;
+import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
+import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+class SalRemoteClientImpl implements SalRemoteClient {
+
+    private static final Logger logger = LoggerFactory.getLogger(SalRemoteClientImpl.class);
+
+    private final RestconfClientContext restconfClientContext;
+    private final SalRemoteServiceBroker salRemoteBroker;
+    private final RuntimeGeneratedMappingServiceImpl mappingService;
+
+    public SalRemoteClientImpl(final URL url) {
+        Preconditions.checkNotNull(url);
+
+        this.mappingService = new RuntimeGeneratedMappingServiceImpl();
+        this.mappingService.setPool(ClassPool.getDefault());
+        this.mappingService.init();
+
+        final ModuleInfoBackedContext moduleInfo = ModuleInfoBackedContext.create();
+        moduleInfo.addModuleInfos(BindingReflections.loadModuleInfos());
+        this.mappingService.onGlobalContextUpdated(moduleInfo.tryToCreateSchemaContext().get());
+
+        try {
+            this.restconfClientContext = new RestconfClientFactory().getRestconfClientContext(url, this.mappingService,
+                    this.mappingService);
+
+            this.salRemoteBroker = new SalRemoteServiceBroker("remote-broker", restconfClientContext);
+            this.salRemoteBroker.start();
+        } catch (UnsupportedProtocolException e) {
+            logger.error("Unsupported protocol {}.", url.getProtocol(), e);
+            throw new IllegalArgumentException("Unsupported protocol.", e);
+        }
+    }
+
+    @Override
+    public ConsumerContext registerConsumer() {
+        return this.salRemoteBroker.registerConsumer(new BindingAwareConsumer() {
+
+            @Override
+            public void onSessionInitialized(ConsumerContext session) {
+            }
+        }, null);
+    }
+
+    @Override
+    public void close() throws Exception {
+        this.restconfClientContext.close();
+        this.salRemoteBroker.close();
+    }
+
+}
index 9410d17007dc1072f16074d27193505805f52e06..003ad9853a32a20d7df06262a6c2490e7f6dfe0d 100644 (file)
@@ -14,7 +14,6 @@ import java.util.concurrent.Future;
 import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
 import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;
 import org.opendaylight.controller.sal.restconf.broker.listeners.RemoteDataChangeNotificationListener;
 import org.opendaylight.controller.sal.restconf.broker.tools.RemoteStreamTools;
 import org.opendaylight.controller.sal.restconf.broker.transactions.RemoteDataModificationTransaction;
@@ -22,12 +21,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controll
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateDataChangeEventSubscriptionInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateDataChangeEventSubscriptionOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.SalRemoteService;
+import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext;
 import org.opendaylight.yangtools.restconf.client.api.event.EventStreamInfo;
 import org.opendaylight.yangtools.restconf.client.api.event.ListenableEventStreamContext;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.DataRoot;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
@@ -45,45 +44,6 @@ public class DataBrokerServiceImpl implements DataBrokerService  {
         this.restconfClientContext = restconfClientContext;
         this.salRemoteService =  this.restconfClientContext.getRpcServiceContext(SalRemoteService.class).getRpcService();
     }
-    @Override
-    public <T extends DataRoot> T getData(DataStoreIdentifier store, Class<T> rootType) {
-        throw new UnsupportedOperationException("Deprecated");
-    }
-
-    @Override
-    public <T extends DataRoot> T getData(DataStoreIdentifier store, T filter) {
-        throw new UnsupportedOperationException("Deprecated");
-    }
-
-    @Override
-    public <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, Class<T> rootType) {
-        throw new UnsupportedOperationException("Deprecated");
-    }
-
-    @Override
-    public <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, T filter) {
-        throw new UnsupportedOperationException("Deprecated");
-    }
-
-    @Override
-    public RpcResult<DataRoot> editCandidateData(DataStoreIdentifier store, DataRoot changeSet) {
-        throw new UnsupportedOperationException("Deprecated");
-    }
-
-    @Override
-    public Future<RpcResult<Void>> commit(DataStoreIdentifier store) {
-        throw new UnsupportedOperationException("Deprecated");
-    }
-
-    @Override
-    public DataObject getData(InstanceIdentifier<? extends DataObject> data) {
-        throw new UnsupportedOperationException("Deprecated");
-    }
-
-    @Override
-    public DataObject getConfigurationData(InstanceIdentifier<?> data) {
-        throw new UnsupportedOperationException("Deprecated");
-    }
 
     @Override
     public DataModificationTransaction beginTransaction() {
@@ -93,16 +53,6 @@ public class DataBrokerServiceImpl implements DataBrokerService  {
         return remoteDataModificationTransaction;
     }
 
-    @Override
-    public void registerChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener) {
-        throw new UnsupportedOperationException("Deprecated");
-    }
-
-    @Override
-    public void unregisterChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener) {
-        throw new UnsupportedOperationException("Deprecated");
-    }
-
     @Override
     public DataObject readConfigurationData(InstanceIdentifier<? extends DataObject> path) {
         try {
@@ -149,22 +99,12 @@ public class DataBrokerServiceImpl implements DataBrokerService  {
         final Map<String,EventStreamInfo> desiredEventStream = RemoteStreamTools.createEventStream(restconfClientContext,streamName);
         ListenableEventStreamContext restConfListenableEventStreamContext = restconfClientContext.getEventStreamContext(desiredEventStream.get(streamName));
         RemoteDataChangeNotificationListener remoteDataChangeNotificationListener = new RemoteDataChangeNotificationListener(listener);
-        restConfListenableEventStreamContext.registerNotificationListener(remoteDataChangeNotificationListener);
-        return new SalRemoteDataListenerRegistration(listener);
-    }
-
-    private class SalRemoteDataListenerRegistration implements ListenerRegistration<DataChangeListener> {
-        private final DataChangeListener dataChangeListener;
-        public SalRemoteDataListenerRegistration(DataChangeListener dataChangeListener){
-            this.dataChangeListener = dataChangeListener;
-        }
-        @Override
-        public DataChangeListener getInstance() {
-            return this.dataChangeListener;
-        }
-        @Override
-        public void close() {
-            //noop
-        }
+        final ListenerRegistration<?> reg = restConfListenableEventStreamContext.registerNotificationListener(remoteDataChangeNotificationListener);
+        return new AbstractListenerRegistration<DataChangeListener>(listener) {
+            @Override
+            protected void removeRegistration() {
+                reg.close();
+            }
+        };
     }
 }
index a332ef77b6591233d3b818f608490c9d963b9ded..54810266a799bc028afd6eeb93eee16730845d30 100644 (file)
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
@@ -18,7 +19,7 @@
                <module>toaster</module>
                <module>toaster-consumer</module>
                <module>toaster-provider</module>
-       </modules>
+  </modules>
 
     <profiles>
       <profile>
           <activeByDefault>false</activeByDefault>
         </activation>
         <modules>
-          <!--module>toaster-it</module -->
+          <module>toaster-it</module>
         </modules>
       </profile>
     </profiles>
 
        <groupId>org.opendaylight.controller.samples</groupId>
-</project>
+</project>
\ No newline at end of file
index 40e99ec28b74920996b962d99964ee9e8bff98dd..fca9783f6152807283bd4f54dd1d5e4e74a588bf 100644 (file)
       <tag>HEAD</tag>
   </scm>
 
+    <properties>
+        <sal-binding-api.version>1.1-SNAPSHOT</sal-binding-api.version>
+        <jmxGeneratorPath>${project.build.directory}/generated-sources/config</jmxGeneratorPath>
+
+    </properties>
+
        <build>
                <plugins>
                        <plugin>
                                <artifactId>maven-bundle-plugin</artifactId>
                                <configuration>
                                        <instructions>
-                                               <Export-Package>org.opendaylight.controller.sample.toaster.provider.api</Export-Package>
-                                               <Private-Package>org.opendaylight.controller.sample.toaster.provider.impl</Private-Package>
-                                               <Bundle-Activator>org.opendaylight.controller.sample.toaster.provider.impl.ToastConsumerImpl</Bundle-Activator>
+                                               <Export-Package>
+                            org.opendaylight.controller.sample.toaster.provider.api,
+                            org.opendaylight.controller.config.yang.toaster-consumer,
+                        </Export-Package>
+                        <Import-Package>*</Import-Package>
                                        </instructions>
                                </configuration>
                        </plugin>
+            <plugin>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>config</id>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+                                    </codeGeneratorClass>
+                                    <outputBaseDir>${jmxGeneratorPath}</outputBaseDir>
+                                    <additionalConfiguration>
+                                        <namespaceToPackage1>
+                                            urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang
+                                        </namespaceToPackage1>
+                                    </additionalConfiguration>
+                                </generator>
+                            </codeGenerators>
+                            <inspectDependencies>true</inspectDependencies>
+                        </configuration>
+                    </execution>
+                </executions>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.controller</groupId>
+                        <artifactId>yang-jmx-generator-plugin</artifactId>
+                        <version>${config.version}</version>
+                    </dependency>
+                </dependencies>
+            </plugin>
+
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <version>1.8</version>
+                <executions>
+                    <execution>
+                        <id>add-source</id>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>add-source</goal>
+                        </goals>
+                        <configuration>
+                            <sources>
+                                <source>${jmxGeneratorPath}</source>
+                            </sources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
                </plugins>
        </build>
 
                        <groupId>org.opendaylight.controller</groupId>
                        <artifactId>sal-binding-api</artifactId>
                </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>config-api</artifactId>
+            <version>${config.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-config</artifactId>
+            <version>${sal-binding-api.version}</version>
+        </dependency>
        </dependencies>
 </project>
diff --git a/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/config/yang/config/toaster_consumer/impl/ToasterConsumerModule.java b/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/config/yang/config/toaster_consumer/impl/ToasterConsumerModule.java
new file mode 100644 (file)
index 0000000..c006a34
--- /dev/null
@@ -0,0 +1,68 @@
+/**
+* Generated file
+
+* Generated from: yang module name: toaster-consumer-impl  yang module local name: toaster-consumer-impl
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Wed Feb 05 11:31:30 CET 2014
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.controller.config.yang.config.toaster_consumer.impl;
+
+import org.opendaylight.controller.sal.binding.api.NotificationListener;
+import org.opendaylight.controller.sample.toaster.provider.api.ToastConsumer;
+import org.opendaylight.controller.sample.toaster.provider.impl.ToastConsumerImpl;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastDone;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastType;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService;
+import org.opendaylight.yangtools.concepts.Registration;
+
+/**
+*
+*/
+public final class ToasterConsumerModule extends org.opendaylight.controller.config.yang.config.toaster_consumer.impl.AbstractToasterConsumerModule
+ {
+
+    public ToasterConsumerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public ToasterConsumerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+            ToasterConsumerModule oldModule, java.lang.AutoCloseable oldInstance) {
+
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    protected void customValidation(){
+        // No need to validate dependencies, since all dependencies have mandatory true flag in yang
+        // config-subsystem will perform the validation
+    }
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+        ToasterService toasterService = getRpcRegistryDependency().getRpcService(ToasterService.class);
+
+        final ToastConsumerImpl consumer = new ToastConsumerImpl(toasterService);
+        final Registration<NotificationListener<ToastDone>> notificationRegistration = getNotificationServiceDependency()
+                .registerNotificationListener(ToastDone.class, consumer);
+
+        final ToasterConsumerRuntimeRegistration runtimeRegistration = getRootRuntimeBeanRegistratorWrapper().register(consumer);
+
+        final class AutoCloseableToastConsumer implements AutoCloseable, ToastConsumer {
+
+            @Override
+            public void close() throws Exception {
+                runtimeRegistration.close();
+                notificationRegistration.close();
+            }
+
+            @Override
+            public boolean createToast(Class<? extends ToastType> type, int doneness) {
+                return consumer.createToast(type, doneness);
+            }
+        }
+
+        return new AutoCloseableToastConsumer();
+    }
+}
diff --git a/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/config/yang/config/toaster_consumer/impl/ToasterConsumerModuleFactory.java b/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/config/yang/config/toaster_consumer/impl/ToasterConsumerModuleFactory.java
new file mode 100644 (file)
index 0000000..f804894
--- /dev/null
@@ -0,0 +1,19 @@
+/**
+* Generated file
+
+* Generated from: yang module name: toaster-consumer-impl  yang module local name: toaster-consumer-impl
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Wed Feb 05 11:31:30 CET 2014
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.controller.config.yang.config.toaster_consumer.impl;
+
+/**
+*
+*/
+public class ToasterConsumerModuleFactory extends org.opendaylight.controller.config.yang.config.toaster_consumer.impl.AbstractToasterConsumerModuleFactory
+{
+
+
+}
index 87e5787ef5c9f63df75c95344ae4ac64e608b76a..5a4b45c71e7ec2d6a09f1557d109b273d19da690 100644 (file)
@@ -7,33 +7,27 @@
  */
 package org.opendaylight.controller.sample.toaster.provider.impl;
 
-import java.util.Hashtable;
 import java.util.concurrent.ExecutionException;
 
-import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareConsumer;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
-import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer;
+import org.opendaylight.controller.config.yang.config.toaster_consumer.impl.ToasterConsumerRuntimeMXBean;
 import org.opendaylight.controller.sal.binding.api.NotificationListener;
-import org.opendaylight.controller.sal.binding.api.NotificationService;
 import org.opendaylight.controller.sample.toaster.provider.api.ToastConsumer;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.MakeToastInputBuilder;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastDone;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastType;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.*;
 import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class ToastConsumerImpl extends AbstractBindingAwareConsumer implements BundleActivator, BindingAwareConsumer, ToastConsumer,
-        NotificationListener<ToastDone> {
+public class ToastConsumerImpl implements
+        ToastConsumer,
+        NotificationListener<ToastDone>,ToasterConsumerRuntimeMXBean {
 
     private static final Logger log = LoggerFactory.getLogger(ToastConsumerImpl.class);
 
     private ToasterService toaster;
 
-    private ConsumerContext session;
+    public ToastConsumerImpl(ToasterService toaster) {
+        this.toaster = toaster;
+    }
 
     @Override
     public boolean createToast(Class<? extends ToastType> type, int doneness) {
@@ -42,45 +36,28 @@ public class ToastConsumerImpl extends AbstractBindingAwareConsumer implements B
         toastInput.setToasterToastType(type);
 
         try {
-            RpcResult<Void> result = getToastService().makeToast(toastInput.build()).get();
+            RpcResult<Void> result = toaster.makeToast(toastInput.build()).get();
 
             if (result.isSuccessful()) {
-                log.trace("Toast was successfuly finished");
+                log.trace("Toast was successfully finished");
             } else {
-                log.warn("Toast was not successfuly finished");
+                log.warn("Toast was not successfully finished");
             }
             return result.isSuccessful();
         } catch (InterruptedException | ExecutionException e) {
-            log.warn("Error occured during toast creation");
+            log.warn("Error occurred during toast creation");
         }
         return false;
 
     }
 
-    @Override
-    @Deprecated
-    protected void startImpl(BundleContext context) {
-        context.registerService(ToastConsumer.class, this, new Hashtable<String,String>());
-    }
-
-    @Override
-    public void onSessionInitialized(ConsumerContext session) {
-        this.session = session;
-        NotificationService notificationService = session.getSALService(NotificationService.class);
-        notificationService.registerNotificationListener(ToastDone.class, this);
-    }
-
     @Override
     public void onNotification(ToastDone notification) {
         log.trace("ToastDone Notification Received: {} ",notification.getToastStatus());
-
     }
 
-    private ToasterService getToastService() {
-        if (toaster == null) {
-            toaster = session.getRpcService(ToasterService.class);
-        }
-        return toaster;
+    @Override
+    public Boolean makeHashBrownToast(Integer doneness) {
+        return createToast(HashBrown.class, doneness);
     }
-
 }
diff --git a/opendaylight/md-sal/samples/toaster-consumer/src/main/yang/toaster-consumer-impl.yang b/opendaylight/md-sal/samples/toaster-consumer/src/main/yang/toaster-consumer-impl.yang
new file mode 100644 (file)
index 0000000..8bc1a5c
--- /dev/null
@@ -0,0 +1,81 @@
+// vi: set smarttab et sw=4 tabstop=4:
+module toaster-consumer-impl {
+
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer:impl";
+    prefix "toaster-consumer-impl";
+
+    import config { prefix config; revision-date 2013-04-05; }
+    import rpc-context { prefix rpcx; revision-date 2013-06-17; }
+
+    import toaster-consumer { prefix toaster-consumer; revision-date 2014-01-31; }
+    import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; }
+
+    description
+        "This module contains the base YANG definitions for
+        toaster-consumer impl implementation.";
+
+    revision "2014-01-31" {
+        description
+            "Initial revision.";
+    }
+
+    // This is the definition of a service implementation
+    identity toaster-consumer-impl {
+            base config:module-type;
+            config:provided-service toaster-consumer:toaster-consumer;
+            config:java-name-prefix ToasterConsumer;
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case toaster-consumer-impl {
+            when "/config:modules/config:module/config:type = 'toaster-consumer-impl'";
+
+            container rpc-registry {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity mdsal:binding-rpc-registry;
+                    }
+                }
+            }
+
+            container notification-service {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity mdsal:binding-notification-service;
+                    }
+                }
+            }
+
+        }
+    }
+
+    augment "/config:modules/config:module/config:state" {
+        case toaster-consumer-impl {
+            when "/config:modules/config:module/config:type = 'toaster-consumer-impl'";
+            rpcx:rpc-context-instance "make-hash-brown-toast-rpc";
+        }
+    }
+
+    identity make-hash-brown-toast-rpc;
+
+    rpc make-hash-brown-toast {
+        input {
+            uses rpcx:rpc-context-ref {
+                refine context-instance {
+                    rpcx:rpc-context-instance make-hash-brown-toast-rpc;
+                }
+            }
+            leaf doneness {
+                type uint16;
+            }
+        }
+        output {
+            leaf result {
+                type boolean;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/samples/toaster-consumer/src/main/yang/toaster-consumer.yang b/opendaylight/md-sal/samples/toaster-consumer/src/main/yang/toaster-consumer.yang
new file mode 100644 (file)
index 0000000..c050ee8
--- /dev/null
@@ -0,0 +1,26 @@
+// vi: set smarttab et sw=4 tabstop=4:
+module toaster-consumer {
+
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer";
+    prefix "toaster-consumer";
+
+    import config { prefix config; revision-date 2013-04-05; }
+
+    description
+        "This module contains the base YANG definitions for
+        toaster-consumer services.";
+
+    revision "2014-01-31" {
+        description
+            "Initial revision.";
+    }
+
+    // This is the definition of a service
+    identity toaster-consumer {
+
+        base "config:service-type";
+
+        config:java-class "org.opendaylight.controller.sample.toaster.provider.api.ToastConsumer";
+    }
+}
\ No newline at end of file
index a1925a53b505a616b1dc3cd6b6d99146a7fe97f7..d61393c22529573f03c76272064fda807d3c807a 100644 (file)
@@ -4,7 +4,7 @@
     <parent>
         <artifactId>sal-samples</artifactId>
         <groupId>org.opendaylight.controller.samples</groupId>
-        <version>1.0-SNAPSHOT</version>
+        <version>1.1-SNAPSHOT</version>
     </parent>
     <artifactId>sample-toaster-it</artifactId>
     <scm>
         <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
     </scm>
 
-    <properties>
-        <exam.version>3.0.0</exam.version>
-        <url.version>1.5.0</url.version>
-    </properties>
 
     <build>
         <plugins>
                     </execution>
                 </executions>
             </plugin>
-            <plugin>
-                <groupId>org.jacoco</groupId>
-                <artifactId>jacoco-maven-plugin</artifactId>
-                <configuration>
-                    <includes>org.opendaylight.controller.*</includes>
-                </configuration>
-                <executions>
-                    <execution>
-                        <id>pre-test</id>
-                        <goals>
-                            <goal>prepare-agent</goal>
-                        </goals>
-                    </execution>
-                    <execution>
-                        <id>post-test</id>
-                        <phase>test</phase>
-                        <goals>
-                            <goal>report</goal>
-                        </goals>
-                    </execution>
-                </executions>
-            </plugin>
         </plugins>
-        <pluginManagement>
-            <plugins>
-                <!--This plugin's configuration is used to store Eclipse 
-                    m2e settings only. It has no influence on the Maven build itself. -->
-                <plugin>
-                    <groupId>org.eclipse.m2e</groupId>
-                    <artifactId>lifecycle-mapping</artifactId>
-                    <version>1.0.0</version>
-                    <configuration>
-                        <lifecycleMappingMetadata>
-                            <pluginExecutions>
-                                <pluginExecution>
-                                    <pluginExecutionFilter>
-                                        <groupId>
-                                            org.ops4j.pax.exam
-                                        </groupId>
-                                        <artifactId>
-                                            maven-paxexam-plugin
-                                        </artifactId>
-                                        <versionRange>
-                                            [1.2.4,)
-                                        </versionRange>
-                                        <goals>
-                                            <goal>
-                                                generate-depends-file
-                                            </goal>
-                                        </goals>
-                                    </pluginExecutionFilter>
-                                    <action>
-                                        <ignore></ignore>
-                                    </action>
-                                </pluginExecution>
-                            </pluginExecutions>
-                        </lifecycleMappingMetadata>
-                    </configuration>
-                </plugin>
-            </plugins>
-        </pluginManagement>
     </build>
 
     <dependencies>
         <dependency>
-            <groupId>org.opendaylight.yangtools.thirdparty</groupId>
-            <artifactId>xtend-lib-osgi</artifactId>
-            <version>2.4.3</version>
-        </dependency>
-        <dependency>
-            <groupId>org.opendaylight.controller.samples</groupId>
-            <artifactId>sample-toaster</artifactId>
-            <version>1.0-SNAPSHOT</version>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-it</artifactId>
+            <version>1.1-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>org.opendaylight.controller.samples</groupId>
             <artifactId>sample-toaster-consumer</artifactId>
-            <version>1.0-SNAPSHOT</version>
+            <version>1.1-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>org.opendaylight.controller.samples</groupId>
             <artifactId>sample-toaster-provider</artifactId>
-            <version>1.0-SNAPSHOT</version>
+            <version>1.1-SNAPSHOT</version>
         </dependency>
         <dependency>
-            <groupId>org.opendaylight.controller</groupId>
-            <artifactId>sal-binding-broker-impl</artifactId>
-            <version>1.0-SNAPSHOT</version>
+            <groupId>org.opendaylight.controller.samples</groupId>
+            <artifactId>sample-toaster</artifactId>
+            <version>1.1-SNAPSHOT</version>
         </dependency>
+
         <dependency>
-            <groupId>org.ops4j.pax.exam</groupId>
-            <artifactId>pax-exam-container-native</artifactId>
-            <version>${exam.version}</version>
-            <scope>test</scope>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
         </dependency>
         <dependency>
             <groupId>org.ops4j.pax.exam</groupId>
             <artifactId>pax-exam-junit4</artifactId>
             <version>${exam.version}</version>
-            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.ops4j.pax.exam</groupId>
             <version>${exam.version}</version>
             <scope>test</scope>
         </dependency>
-
         <dependency>
-            <groupId>org.opendaylight.controller</groupId>
-            <artifactId>config-manager</artifactId>
-            <version>0.2.3-SNAPSHOT</version>
+            <groupId>org.ops4j.pax.exam</groupId>
+            <artifactId>pax-exam-container-native</artifactId>
+            <version>${exam.version}</version>
+            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>equinoxSDK381</groupId>
             <version>3.8.1.v20120830-144521</version>
             <scope>test</scope>
         </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>log4j-over-slf4j</artifactId>
-            <version>1.7.2</version>
-        </dependency>
-        <dependency>
-            <groupId>ch.qos.logback</groupId>
-            <artifactId>logback-core</artifactId>
-            <version>1.0.9</version>
-        </dependency>
-        <dependency>
-            <groupId>ch.qos.logback</groupId>
-            <artifactId>logback-classic</artifactId>
-            <version>1.0.9</version>
-        </dependency>
-        <dependency>
-            <groupId>org.opendaylight.yangtools.thirdparty</groupId>
-            <artifactId>antlr4-runtime-osgi-nohead</artifactId>
-            <version>4.0</version>
-        </dependency>
     </dependencies>
 </project>
index a7e1e9b44522e4e465c5c474a2c302d3d82bb224..38a4dd46617405c148022d4622a3b200b9182b80 100644 (file)
  */
 package org.opendaylight.controller.sample.toaster.it;
 
+import static org.junit.Assert.assertEquals;
+import static org.opendaylight.controller.test.sal.binding.it.TestHelper.*;
+import static org.ops4j.pax.exam.CoreOptions.*;
+
+import javax.inject.Inject;
+import javax.management.JMX;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.config.yang.config.toaster_consumer.impl.ToasterConsumerRuntimeMXBean;
+import org.opendaylight.controller.config.yang.config.toaster_provider.impl.ToasterProviderRuntimeMXBean;
 import org.opendaylight.controller.sample.toaster.provider.api.ToastConsumer;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.HashBrown;
 import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.WhiteBread;
 import org.ops4j.pax.exam.Configuration;
 import org.ops4j.pax.exam.Option;
 import org.ops4j.pax.exam.junit.PaxExam;
-import org.osgi.framework.BundleContext;
-
-import javax.inject.Inject;
-
-import static org.junit.Assert.assertTrue;
-import static org.ops4j.pax.exam.CoreOptions.junitBundles;
-import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
-import static org.ops4j.pax.exam.CoreOptions.options;
-import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+import org.ops4j.pax.exam.options.DefaultCompositeOption;
+import org.ops4j.pax.exam.util.Filter;
 import org.ops4j.pax.exam.util.PathUtils;
 
+import java.lang.management.ManagementFactory;
+
 @RunWith(PaxExam.class)
 public class ToasterTest {
 
-    public static final String ODL = "org.opendaylight.controller";
-    public static final String YANG = "org.opendaylight.yangtools";
-    public static final String CONTROLLER = "org.opendaylight.controller";
-    public static final String YANGTOOLS = "org.opendaylight.yangtools";
-    
-    
-    public static final String SAMPLE = "org.opendaylight.controller.samples";
+    @Inject
+    @Filter(timeout=60*1000)
+    ToastConsumer toastConsumer;
 
-    @Test
-    public void properInitialized() throws Exception {
+    @Configuration
+    public Option[] config() {
+        return options(systemProperty("osgi.console").value("2401"), mavenBundle("org.slf4j", "slf4j-api")
+                .versionAsInProject(), //
+                          mavenBundle("org.slf4j", "log4j-over-slf4j").versionAsInProject(), //
+
+                                systemProperty("logback.configurationFile").value(
+                        "file:" + PathUtils.getBaseDir()
+                                + "/src/test/resources/logback.xml"),
+                mavenBundle("ch.qos.logback", "logback-core").versionAsInProject(), //
+                mavenBundle("ch.qos.logback", "logback-classic").versionAsInProject(), //
+                systemProperty("osgi.bundles.defaultStartLevel").value("4"),
 
-        Thread.sleep(500); // Waiting for services to get wired.
+                toasterBundles(),
+                mdSalCoreBundles(),
 
-        assertTrue(consumer.createToast(WhiteBread.class, 5));
+                bindingAwareSalBundles(),
+                configMinumumBundles(),
+                // BASE Models
+                baseModelBundles(),
+                flowCapableModelBundles(),
 
+                // Set fail if unresolved bundle present
+                systemProperty("pax.exam.osgi.unresolved.fail").value("true"),
+                junitAndMockitoBundles());
     }
 
-    @Inject
-    BindingAwareBroker broker;
+    private Option toasterBundles() {
+        return new DefaultCompositeOption(
+                mavenBundle("org.opendaylight.controller.samples", "sample-toaster-provider").versionAsInProject(),
+                mavenBundle("org.opendaylight.controller.samples", "sample-toaster-consumer").versionAsInProject(),
+                mavenBundle("org.opendaylight.controller.samples", "sample-toaster").versionAsInProject()
+        );
+    }
 
-    @Inject
-    ToastConsumer consumer;
+    @Test
+    public void testToaster() throws Exception {
 
-    @Inject
-    BundleContext ctx;
+        MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
+        ObjectName consumerOn = new ObjectName("org.opendaylight.controller:instanceName=toaster-consumer-impl,type=RuntimeBean,moduleFactoryName=toaster-consumer-impl");
+        ObjectName providerOn = new ObjectName("org.opendaylight.controller:instanceName=toaster-provider-impl,type=RuntimeBean,moduleFactoryName=toaster-provider-impl");
 
-    @Configuration
-    public Option[] config() {
-        return options(systemProperty("osgi.console").value("2401"), 
-                systemProperty("logback.configurationFile").value(
-                    "file:" + PathUtils.getBaseDir()
-                    + "/src/test/resources/logback.xml"),
-                mavenBundle("org.slf4j", "slf4j-api").versionAsInProject(), //
-                mavenBundle("org.slf4j", "log4j-over-slf4j").versionAsInProject(), //
-                mavenBundle("ch.qos.logback", "logback-core").versionAsInProject(), //
-                mavenBundle("ch.qos.logback", "logback-classic").versionAsInProject(), //
-                
-                mavenBundle(ODL, "sal-common").versionAsInProject(), //
-                mavenBundle(ODL, "sal-common-api").versionAsInProject(),//
-                mavenBundle(ODL, "sal-common-impl").versionAsInProject(), //
-                mavenBundle(ODL, "sal-common-util").versionAsInProject(), //
-                
-                mavenBundle(ODL, "config-api").versionAsInProject(), //
-                mavenBundle(ODL, "config-manager").versionAsInProject(), //
-                mavenBundle("commons-io", "commons-io").versionAsInProject(),
-                mavenBundle("org.apache.commons", "commons-lang3").versionAsInProject(),
-                
-                mavenBundle(CONTROLLER, "sal-binding-api").versionAsInProject(), //
-                mavenBundle(CONTROLLER, "sal-binding-config").versionAsInProject(),
-                mavenBundle(CONTROLLER, "sal-binding-broker-impl").versionAsInProject(), //
-                mavenBundle("org.javassist", "javassist").versionAsInProject(), //
-                mavenBundle(CONTROLLER, "sal-common-util").versionAsInProject(), //
-        
-                mavenBundle(YANGTOOLS, "yang-data-api").versionAsInProject(), //
-                mavenBundle(YANGTOOLS, "yang-data-impl").versionAsInProject(), //
-                mavenBundle(YANGTOOLS, "yang-model-api").versionAsInProject(), //
-                mavenBundle(YANGTOOLS, "yang-model-util").versionAsInProject(), //
-                mavenBundle(YANGTOOLS, "yang-parser-api").versionAsInProject(),
-                mavenBundle(YANGTOOLS, "yang-parser-impl").versionAsInProject(),
-                
-                
-                mavenBundle(YANGTOOLS, "binding-generator-spi").versionAsInProject(), //
-                mavenBundle(YANGTOOLS, "binding-model-api").versionAsInProject(), //
-                mavenBundle(YANGTOOLS, "binding-generator-util").versionAsInProject(),
-                mavenBundle(YANGTOOLS, "yang-parser-impl").versionAsInProject(),
-                mavenBundle(YANGTOOLS, "binding-type-provider").versionAsInProject(),
-                mavenBundle(YANGTOOLS, "binding-generator-api").versionAsInProject(),
-                mavenBundle(YANGTOOLS, "binding-generator-spi").versionAsInProject(),
-                mavenBundle(YANGTOOLS, "binding-generator-impl").versionAsInProject(),
-                
-                
-                mavenBundle(CONTROLLER, "sal-core-api").versionAsInProject().update(), //
-                mavenBundle(CONTROLLER, "sal-broker-impl").versionAsInProject(), //
-                mavenBundle(CONTROLLER, "sal-core-spi").versionAsInProject().update(), //
-                
-                mavenBundle(YANGTOOLS + ".thirdparty", "antlr4-runtime-osgi-nohead").versionAsInProject(), //
-                
-                mavenBundle(SAMPLE, "sample-toaster").versionAsInProject(), //
-                mavenBundle(SAMPLE, "sample-toaster-consumer").versionAsInProject(), //
-                mavenBundle(SAMPLE, "sample-toaster-provider").versionAsInProject(), //
-                mavenBundle(YANG, "concepts").versionAsInProject(),
-                mavenBundle(YANG, "yang-binding").versionAsInProject(), //
-                mavenBundle(YANG, "yang-common").versionAsInProject(), //
-                mavenBundle(YANG+".thirdparty", "xtend-lib-osgi").versionAsInProject(),
-                mavenBundle("com.google.guava", "guava").versionAsInProject(), //
-                mavenBundle("org.javassist", "javassist").versionAsInProject(),
-                junitBundles()
-                );
+        long toastsMade = (long) platformMBeanServer.getAttribute(providerOn, "ToastsMade");
+        assertEquals(0, toastsMade);
+
+        boolean toasts = true;
+
+        // Make toasts using OSGi service
+        toasts &= toastConsumer.createToast(HashBrown.class, 4);
+        toasts &= toastConsumer.createToast(WhiteBread.class, 8);
+
+        // Make toast using JMX/config-subsystem
+        toasts &= (Boolean)platformMBeanServer.invoke(consumerOn, "makeHashBrownToast", new Object[]{4}, new String[]{Integer.class.getName()});
+
+        Assert.assertTrue("Not all toasts done by " + toastConsumer, toasts);
+
+        // Verify toasts made count on provider via JMX/config-subsystem
+        toastsMade = (long) platformMBeanServer.getAttribute(providerOn, "ToastsMade");
+        assertEquals(3, toastsMade);
     }
 
 }
diff --git a/opendaylight/md-sal/samples/toaster-it/src/test/resources/controller.xml b/opendaylight/md-sal/samples/toaster-it/src/test/resources/controller.xml
new file mode 100644 (file)
index 0000000..7a282db
--- /dev/null
@@ -0,0 +1,250 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<persisted-snapshots>
+    <snapshots>
+        <snapshot>
+            <required-capabilities>
+                <capability>urn:opendaylight:l2:types?module=opendaylight-l2-types&amp;revision=2013-08-27</capability>
+                <capability>
+                    urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&amp;revision=2013-10-28
+                </capability>
+                <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom?module=opendaylight-md-sal-dom&amp;revision=2013-10-28</capability>
+                <capability>
+                    urn:opendaylight:params:xml:ns:yang:controller:config?module=config&amp;revision=2013-04-05
+                </capability>
+                <capability>urn:ietf:params:netconf:capability:candidate:1.0</capability>
+                <capability>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&amp;revision=2010-10-04</capability>
+                <capability>urn:ietf:params:xml:ns:yang:rpc-context?module=rpc-context&amp;revision=2013-06-17
+                </capability>
+                <capability>
+                    urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&amp;revision=2013-10-28
+                </capability>
+                <capability>urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&amp;revision=2010-09-24
+                </capability>
+                <capability>urn:ietf:params:netconf:capability:rollback-on-error:1.0</capability>
+                <capability>urn:ietf:params:xml:ns:yang:ietf-yang-types?module=ietf-yang-types&amp;revision=2010-09-24
+                </capability>
+                <capability>
+                    urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&amp;revision=2013-10-28
+                </capability>
+                <capability>urn:opendaylight:params:xml:ns:yang:controller:logback:config?module=config-logging&amp;revision=2013-07-16</capability>
+                <capability>urn:opendaylight:yang:extension:yang-ext?module=yang-ext&amp;revision=2013-07-09
+                </capability>
+                <capability>
+                    urn:opendaylight:params:xml:ns:yang:controller:md:sal:common?module=opendaylight-md-sal-common&amp;revision=2013-10-28
+                </capability>
+                <capability>http://netconfcentral.org/ns/toaster?module=toaster&amp;revision=2009-11-20</capability>
+                <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer?module=toaster-consumer&amp;revision=2014-01-31</capability>
+                <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer:impl?module=toaster-consumer-impl&amp;revision=2014-01-31</capability>
+                <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider?module=toaster-provider&amp;revision=2014-01-31</capability>
+                <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl?module=toaster-provider-impl&amp;revision=2014-01-31</capability>
+
+            </required-capabilities>
+            <configuration>
+
+                <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+                    <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+                        <module>
+                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl">
+                                prefix:toaster-provider-impl
+                            </type>
+                            <name>toaster-provider-impl</name>
+
+                            <rpc-registry>
+                                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
+                                <name>binding-rpc-broker</name>
+                            </rpc-registry>
+
+                            <notification-service>
+                                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
+                                    binding:binding-notification-service
+                                </type>
+                                <name>ref_binding-notification-broker</name>
+                            </notification-service>
+                        </module>
+
+                        <module>
+                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer:impl">
+                                prefix:toaster-consumer-impl
+                            </type>
+                            <name>toaster-consumer-impl</name>
+
+                            <rpc-registry>
+                                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
+                                <name>binding-rpc-broker</name>
+                            </rpc-registry>
+
+                            <notification-service>
+                                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
+                                    binding:binding-notification-service
+                                </type>
+                                <name>ref_binding-notification-broker</name>
+                            </notification-service>
+                        </module>
+
+                        <module>
+                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
+                                prefix:schema-service-singleton
+                            </type>
+                            <name>yang-schema-service</name>
+                        </module>
+                        <module>
+                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
+                                prefix:hash-map-data-store
+                            </type>
+                            <name>hash-map-data-store</name>
+                        </module>
+                        <module>
+                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
+                                prefix:dom-broker-impl
+                            </type>
+                            <name>dom-broker</name>
+                            <data-store xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
+                                <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
+                                    dom:dom-data-store
+                                </type>
+                                <name>ref_hash-map-data-store</name>
+                            </data-store>
+                        </module>
+                        <module>
+                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                                prefix:binding-broker-impl
+                            </type>
+                            <name>binding-broker-impl</name>
+                            <notification-service
+                                    xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
+                                    binding:binding-notification-service
+                                </type>
+                                <name>ref_binding-notification-broker</name>
+                            </notification-service>
+                            <data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
+                                    binding:binding-data-broker
+                                </type>
+                                <name>ref_binding-data-broker</name>
+                            </data-broker>
+                        </module>
+                        <module>
+                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                                prefix:runtime-generated-mapping
+                            </type>
+                            <name>runtime-mapping-singleton</name>
+                        </module>
+                        <module>
+                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                                prefix:binding-notification-broker
+                            </type>
+                            <name>binding-notification-broker</name>
+                        </module>
+                        <module>
+                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                                prefix:binding-data-broker
+                            </type>
+                            <name>binding-data-broker</name>
+                            <dom-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                                <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
+                                    dom:dom-broker-osgi-registry
+                                </type>
+                                <name>ref_dom-broker</name>
+                            </dom-broker>
+                            <mapping-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                                    binding:binding-dom-mapping-service
+                                </type>
+                                <name>ref_runtime-mapping-singleton</name>
+                            </mapping-service>
+                        </module>
+                    </modules>
+
+                    <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+                        <service>
+                            <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
+                                dom:schema-service
+                            </type>
+                            <instance>
+                                <name>ref_yang-schema-service</name>
+                                <provider>
+                                    /config/modules/module[name='schema-service-singleton']/instance[name='yang-schema-service']
+                                </provider>
+                            </instance>
+                        </service>
+                        <service>
+                            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
+                                binding:binding-notification-service
+                            </type>
+                            <instance>
+                                <name>ref_binding-notification-broker</name>
+                                <provider>
+                                    /config/modules/module[name='binding-notification-broker']/instance[name='binding-notification-broker']
+                                </provider>
+                            </instance>
+                        </service>
+                        <service>
+                            <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
+                                dom:dom-data-store
+                            </type>
+                            <instance>
+                                <name>ref_hash-map-data-store</name>
+                                <provider>
+                                    /config/modules/module[name='hash-map-data-store']/instance[name='hash-map-data-store']
+                                </provider>
+                            </instance>
+                        </service>
+                        <service>
+                            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
+                            <instance>
+                                <name>binding-rpc-broker</name>
+                                <provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
+                            </instance>
+                        </service>
+                        <service>
+                            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
+                                binding:binding-broker-osgi-registry
+                            </type>
+                            <instance>
+                                <name>ref_binding-broker-impl</name>
+                                <provider>
+                                    /config/modules/module[name='binding-broker-impl']/instance[name='binding-broker-impl']
+                                </provider>
+                            </instance>
+                        </service>
+                        <service>
+                            <type xmlns:binding-impl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                                binding-impl:binding-dom-mapping-service
+                            </type>
+                            <instance>
+                                <name>ref_runtime-mapping-singleton</name>
+                                <provider>
+                                    /config/modules/module[name='runtime-generated-mapping']/instance[name='runtime-mapping-singleton']
+                                </provider>
+                            </instance>
+                        </service>
+                        <service>
+                            <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
+                                dom:dom-broker-osgi-registry
+                            </type>
+                            <instance>
+                                <name>ref_dom-broker</name>
+                                <provider>/config/modules/module[name='dom-broker-impl']/instance[name='dom-broker']
+                                </provider>
+                            </instance>
+                        </service>
+                        <service>
+                            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
+                                binding:binding-data-broker
+                            </type>
+                            <instance>
+                                <name>ref_binding-data-broker</name>
+                                <provider>
+                                    /config/modules/module[name='binding-data-broker']/instance[name='binding-data-broker']
+                                </provider>
+                            </instance>
+                        </service>
+                    </services>
+                </data>
+
+            </configuration>
+        </snapshot>
+
+    </snapshots>
+</persisted-snapshots>
index 2d63ce57448f88b77a39b1bcb0525b9721c08370..f904f9726efce6c236526f318654fab49a81f49a 100644 (file)
@@ -7,7 +7,10 @@
     </encoder>
   </appender>
 
-  <root level="error">
+
+  <logger name="org.opendaylight.yangtools.yang.parser" level="ERROR"/>
+
+  <root level="debug">
     <appender-ref ref="STDOUT" />
   </root>
 </configuration>
index ca1e3b468941af54cd4fd0b9e6e68b5c45e9ed52..1a540fe9497fc51e4bb651fc7ea73f37bae69dc1 100644 (file)
   </scm>
 
 
+    <properties>
+        <jmxGeneratorPath>${project.build.directory}/generated-sources/config</jmxGeneratorPath>
+        <sal-binding-api.version>1.1-SNAPSHOT</sal-binding-api.version>
+    </properties>
+
     <build>
         <plugins>
             <plugin>
                 <artifactId>maven-bundle-plugin</artifactId>
                 <configuration>
                     <instructions>
-                        <Bundle-Activator>org.opendaylight.controller.sample.toaster.provider.ToasterProvider</Bundle-Activator>
+                        <Export-Package>
+                            org.opendaylight.controller.config.yang.toaster_provider,
+                        </Export-Package>
+                        <Import-Package>*</Import-Package>
                     </instructions>
                 </configuration>
             </plugin>
+            <plugin>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>config</id>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+                                    </codeGeneratorClass>
+                                    <outputBaseDir>${jmxGeneratorPath}</outputBaseDir>
+                                    <additionalConfiguration>
+                                        <namespaceToPackage1>
+                                            urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang
+                                        </namespaceToPackage1>
+                                    </additionalConfiguration>
+                                </generator>
+                            </codeGenerators>
+                            <inspectDependencies>true</inspectDependencies>
+                        </configuration>
+                    </execution>
+                </executions>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.controller</groupId>
+                        <artifactId>yang-jmx-generator-plugin</artifactId>
+                        <version>${config.version}</version>
+                    </dependency>
+                </dependencies>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <version>1.8</version>
+                <executions>
+                    <execution>
+                        <id>add-source</id>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>add-source</goal>
+                        </goals>
+                        <configuration>
+                            <sources>
+                                <source>${jmxGeneratorPath}</source>
+                            </sources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
         </plugins>
     </build>
 
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>sal-common-util</artifactId>
         </dependency>
+       <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-config</artifactId>
+        </dependency>
+       <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>config-api</artifactId>
+        </dependency>
     </dependencies>
 </project>
diff --git a/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/config/yang/config/toaster_provider/impl/ToasterProviderModule.java b/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/config/yang/config/toaster_provider/impl/ToasterProviderModule.java
new file mode 100644 (file)
index 0000000..1029105
--- /dev/null
@@ -0,0 +1,72 @@
+/**
+* Generated file
+
+* Generated from: yang module name: toaster-provider-impl  yang module local name: toaster-provider-impl
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Wed Feb 05 11:05:32 CET 2014
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.controller.config.yang.config.toaster_provider.impl;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sample.toaster.provider.OpendaylightToaster;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.Toaster;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterData;
+import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService;
+
+/**
+*
+*/
+public final class ToasterProviderModule extends org.opendaylight.controller.config.yang.config.toaster_provider.impl.AbstractToasterProviderModule
+ {
+
+    public ToasterProviderModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public ToasterProviderModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+            ToasterProviderModule oldModule, java.lang.AutoCloseable oldInstance) {
+
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    protected void customValidation() {
+        // No need to validate dependencies, since all dependencies have mandatory true flag in yang
+        // config-subsystem will perform the validation for dependencies
+    }
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+        final OpendaylightToaster opendaylightToaster = new OpendaylightToaster();
+
+        // Register to md-sal
+        opendaylightToaster.setNotificationProvider(getNotificationServiceDependency());
+        final BindingAwareBroker.RpcRegistration<ToasterService> rpcRegistration = getRpcRegistryDependency()
+                .addRpcImplementation(ToasterService.class, opendaylightToaster);
+
+        // Register runtimeBean for toaster statistics via JMX
+        final ToasterProviderRuntimeRegistration runtimeReg = getRootRuntimeBeanRegistratorWrapper().register(
+                opendaylightToaster);
+
+        // Wrap toaster as AutoCloseable and close registrations to md-sal at
+        // close()
+        final class AutoCloseableToaster implements AutoCloseable, ToasterData {
+
+            @Override
+            public void close() throws Exception {
+                rpcRegistration.close();
+                runtimeReg.close();
+            }
+
+            @Override
+            public Toaster getToaster() {
+                return opendaylightToaster.getToaster();
+            }
+        }
+
+        return new AutoCloseableToaster();
+    }
+
+}
diff --git a/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/config/yang/config/toaster_provider/impl/ToasterProviderModuleFactory.java b/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/config/yang/config/toaster_provider/impl/ToasterProviderModuleFactory.java
new file mode 100644 (file)
index 0000000..53a5071
--- /dev/null
@@ -0,0 +1,19 @@
+/**
+* Generated file
+
+* Generated from: yang module name: toaster-provider-impl  yang module local name: toaster-provider-impl
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Wed Feb 05 11:05:32 CET 2014
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.controller.config.yang.config.toaster_provider.impl;
+
+/**
+*
+*/
+public class ToasterProviderModuleFactory extends org.opendaylight.controller.config.yang.config.toaster_provider.impl.AbstractToasterProviderModuleFactory
+{
+
+
+}
index c3b9716783ef0b940484d2b65d7e8ccc227b6e57..a484154edf1703819b9c7675ace6675b53992470 100644 (file)
@@ -13,7 +13,9 @@ import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicLong;
 
+import org.opendaylight.controller.config.yang.config.toaster_provider.impl.ToasterProviderRuntimeMXBean;
 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
 import org.opendaylight.controller.sal.common.util.Futures;
 import org.opendaylight.controller.sal.common.util.Rpcs;
@@ -31,7 +33,7 @@ import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class OpendaylightToaster implements ToasterData, ToasterService {
+public class OpendaylightToaster implements ToasterData, ToasterService, ToasterProviderRuntimeMXBean {
 
     private static final Logger log = LoggerFactory.getLogger(OpendaylightToaster.class);
 
@@ -102,6 +104,13 @@ public class OpendaylightToaster implements ToasterData, ToasterService {
         log.trace("Toast: {} doneness: {}", toastType, toastDoneness);
     }
 
+    private final AtomicLong toastsMade = new AtomicLong(0);
+
+    @Override
+    public Long getToastsMade() {
+        return toastsMade.get();
+    }
+
     private class MakeToastTask implements Callable<RpcResult<Void>> {
 
         final MakeToastInput toastRequest;
@@ -120,6 +129,9 @@ public class OpendaylightToaster implements ToasterData, ToasterService {
             log.trace("Toast Done");
             logToastInput(toastRequest);
             currentTask = null;
+
+            toastsMade.incrementAndGet();
+
             return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
         }
     }
diff --git a/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/ToasterProvider.java b/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/ToasterProvider.java
deleted file mode 100644 (file)
index ae482ed..0000000
+++ /dev/null
@@ -1,49 +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.sample.toaster.provider;
-
-import java.util.Collection;
-import java.util.Collections;
-
-import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
-import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
-import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService;
-import org.opendaylight.yangtools.yang.binding.RpcService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ToasterProvider extends AbstractBindingAwareProvider {
-    private static final Logger log = LoggerFactory.getLogger(ToasterProvider.class);
-
-    private ProviderContext providerContext;
-    private final OpendaylightToaster toaster;
-
-    public ToasterProvider() {
-        toaster = new OpendaylightToaster();
-    }
-
-    @Override
-    public void onSessionInitiated(ProviderContext session) {
-        log.info("Provider Session initialized");
-
-        this.providerContext = session;
-        toaster.setNotificationProvider(session.getSALService(NotificationProviderService.class));
-        providerContext.addRpcImplementation(ToasterService.class, toaster);
-    }
-
-    @Override
-    public Collection<? extends RpcService> getImplementations() {
-        return Collections.emptySet();
-    }
-
-    @Override
-    public Collection<? extends ProviderFunctionality> getFunctionality() {
-        return Collections.emptySet();
-    }
-}
diff --git a/opendaylight/md-sal/samples/toaster-provider/src/main/yang/toaster-provider-impl.yang b/opendaylight/md-sal/samples/toaster-provider/src/main/yang/toaster-provider-impl.yang
new file mode 100644 (file)
index 0000000..0be8874
--- /dev/null
@@ -0,0 +1,63 @@
+// vi: set smarttab et sw=4 tabstop=4:
+module toaster-provider-impl {
+
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl";
+    prefix "toaster-provider-impl";
+
+    import config { prefix config; revision-date 2013-04-05; }
+    import toaster-provider { prefix toaster-provider; revision-date 2014-01-31; }
+    import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; }
+
+    description
+        "This module contains the base YANG definitions for
+        toaster-provider impl implementation.";
+
+    revision "2014-01-31" {
+        description
+            "Initial revision.";
+    }
+
+    // This is the definition of a service implementation
+    identity toaster-provider-impl {
+            base config:module-type;
+            config:provided-service toaster-provider:toaster-provider;
+            config:java-name-prefix ToasterProvider;
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case toaster-provider-impl {
+            when "/config:modules/config:module/config:type = 'toaster-provider-impl'";
+
+            container rpc-registry {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity mdsal:binding-rpc-registry;
+                    }
+                }
+            }
+
+            container notification-service {
+                uses config:service-ref {
+                    refine type {
+                        mandatory true;
+                        config:required-identity mdsal:binding-notification-service;
+                    }
+                }
+            }
+
+        }
+    }
+
+    augment "/config:modules/config:module/config:state" {
+        case toaster-provider-impl {
+            when "/config:modules/config:module/config:type = 'toaster-provider-impl'";
+
+            leaf toasts-made {
+                type uint32;
+            }
+
+        }
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/samples/toaster-provider/src/main/yang/toaster-provider.yang b/opendaylight/md-sal/samples/toaster-provider/src/main/yang/toaster-provider.yang
new file mode 100644 (file)
index 0000000..a5fba07
--- /dev/null
@@ -0,0 +1,26 @@
+// vi: set smarttab et sw=4 tabstop=4:
+module toaster-provider {
+
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider";
+    prefix "toaster-provider";
+
+    import config { prefix config; revision-date 2013-04-05; }
+
+    description
+        "This module contains the base YANG definitions for
+        toaster-provider services.";
+
+    revision "2014-01-31" {
+        description
+            "Initial revision.";
+    }
+
+    // This is the definition of a service
+    identity toaster-provider {
+
+        base "config:service-type";
+
+        config:java-class "org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterData";
+    }
+}
\ No newline at end of file
index 599fd714b8448452cd7da82d7784247c2f9a48cc..ad6d814c1b106382a33a066e0572ae5bc4a6436b 100644 (file)
@@ -19,7 +19,6 @@
             <plugin>
                 <groupId>org.opendaylight.yangtools</groupId>
                 <artifactId>yang-maven-plugin</artifactId>
-                <version>${yangtools.version}</version>
                 <executions>
                     <execution>
                         <goals>
index 6db7f3a56df6baea28ec772863dab3794df818a2..f8993a09e7e7ed62d5ae2727df2a05f26db4e92b 100644 (file)
@@ -4,7 +4,7 @@
     <parent>
         <artifactId>netconf-subsystem</artifactId>
         <groupId>org.opendaylight.controller</groupId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
     </parent>
     <artifactId>config-netconf-connector</artifactId>
     <name>${project.artifactId}</name>
index 592d8e4f3b657933b99144f5c769adf4895a5baf..b3327f54fd23ece86371f29ada3c97ae036c4a92 100644 (file)
@@ -8,9 +8,8 @@
 
 package org.opendaylight.controller.netconf.confignetconfconnector.operations;
 
-import java.util.HashMap;
-import java.util.Map;
-
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.config.api.ValidationException;
 import org.opendaylight.controller.config.api.jmx.CommitStatus;
 import org.opendaylight.controller.config.util.ConfigRegistryClient;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
@@ -25,6 +24,9 @@ import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
+import java.util.HashMap;
+import java.util.Map;
+
 public class Commit extends AbstractConfigNetconfOperation {
 
     private static final Logger logger = LoggerFactory.getLogger(Commit.class);
@@ -55,16 +57,19 @@ public class Commit extends AbstractConfigNetconfOperation {
         try {
             status = this.transactionProvider.commitTransaction();
         } catch (final IllegalStateException e) {
+            // TODO Illegal state thrown when no transaction yet for user
+            // Throw other exception type, or create transaction automatically
             logger.warn("Commit failed: ", e);
             final Map<String, String> errorInfo = new HashMap<>();
             errorInfo.put(ErrorTag.operation_failed.name(),
                     "Operation failed. Use 'get-config' or 'edit-config' before triggering 'commit' operation");
             throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.application, ErrorTag.operation_failed,
                     ErrorSeverity.error, errorInfo);
-        } catch (final NetconfDocumentedException e) {
-            throw new NetconfDocumentedException(
-                    "Unable to retrieve config snapshot after commit for persister, details: " + e.getMessage(),
-                    ErrorType.application, ErrorTag.operation_failed, ErrorSeverity.error, e.getErrorInfo());
+        } catch (ValidationException e) {
+            throw NetconfDocumentedException.wrap(e);
+        } catch (ConflictingVersionException e) {
+            throw NetconfDocumentedException.wrap(e);
+
         }
         logger.trace("Datastore {} committed successfully: {}", Datastore.candidate, status);
 
index 3da02a84302992ce20c4d66927020034e65b9630..8965deb6303a716143d7b54a064c58d79758bfbe 100644 (file)
@@ -8,9 +8,6 @@
 
 package org.opendaylight.controller.netconf.confignetconfconnector.operations;
 
-import java.util.HashMap;
-import java.util.Map;
-
 import org.opendaylight.controller.config.util.ConfigRegistryClient;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
@@ -24,6 +21,9 @@ import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
+import java.util.HashMap;
+import java.util.Map;
+
 public class DiscardChanges extends AbstractConfigNetconfOperation {
 
     public static final String DISCARD = "discard-changes";
@@ -53,6 +53,7 @@ public class DiscardChanges extends AbstractConfigNetconfOperation {
         try {
             fromXml(xml);
         } catch (final IllegalArgumentException e) {
+            //FIXME where can IllegalStateException  be thrown?
             logger.warn("Rpc error: {}", ErrorTag.bad_attribute, e);
             final Map<String, String> errorInfo = new HashMap<>();
             errorInfo.put(ErrorTag.bad_attribute.name(), e.getMessage());
@@ -63,6 +64,7 @@ public class DiscardChanges extends AbstractConfigNetconfOperation {
         try {
             this.transactionProvider.abortTransaction();
         } catch (final IllegalStateException e) {
+            //FIXME where can IllegalStateException  be thrown?
             logger.warn("Abort failed: ", e);
             final Map<String, String> errorInfo = new HashMap<>();
             errorInfo
index 24611c26cd5030637daed3c3a0aa884afa842a4e..017b5e6c39a3f1dfa0865ca07b5e75a71e67183a 100644 (file)
@@ -66,12 +66,14 @@ public class Validate extends AbstractConfigNetconfOperation {
         try {
             checkXml(xml);
         } catch (IllegalStateException e) {
+            //FIXME where can IllegalStateException  be thrown? I see precondition that guards for programming bugs..
             logger.warn("Rpc error: {}", ErrorTag.missing_attribute, e);
             final Map<String, String> errorInfo = new HashMap<>();
             errorInfo.put(ErrorTag.missing_attribute.name(), "Missing value of datastore attribute");
             throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.rpc, ErrorTag.missing_attribute,
                     ErrorSeverity.error, errorInfo);
         } catch (final IllegalArgumentException e) {
+            // FIXME use checked exception if it has domain meaning
             logger.warn("Rpc error: {}", ErrorTag.bad_attribute, e);
             final Map<String, String> errorInfo = new HashMap<>();
             errorInfo.put(ErrorTag.bad_attribute.name(), e.getMessage());
@@ -83,10 +85,7 @@ public class Validate extends AbstractConfigNetconfOperation {
             transactionProvider.validateTransaction();
         } catch (ValidationException e) {
             logger.warn("Validation failed", e);
-            final Map<String, String> errorInfo = new HashMap<>();
-            errorInfo.put(ErrorTag.operation_failed.name(), "Validation failed");
-            throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.application, ErrorTag.operation_failed,
-                    ErrorSeverity.error, errorInfo);
+            throw NetconfDocumentedException.wrap(e);
         } catch (IllegalStateException e) {
             logger.warn("Validation failed", e);
             final Map<String, String> errorInfo = new HashMap<>();
index 97535ba1e2a6a576dd4f21444e7ce5f8e418d8c9..bd85f948f5325a8a6756fd5ab236bfb66aaba986 100644 (file)
@@ -12,7 +12,6 @@ import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Multimap;
-import org.opendaylight.controller.config.api.JmxAttributeValidationException;
 import org.opendaylight.controller.config.api.ValidationException;
 import org.opendaylight.controller.config.util.ConfigRegistryClient;
 import org.opendaylight.controller.config.util.ConfigTransactionClient;
@@ -87,7 +86,11 @@ public class EditConfig extends AbstractConfigNetconfOperation {
             EditConfigXmlParser.EditConfigExecution editConfigExecution) throws NetconfDocumentedException {
         try {
             set(configRegistryClient, editConfigExecution);
-        } catch (IllegalStateException | JmxAttributeValidationException | ValidationException e) {
+
+        } catch (IllegalStateException e) {
+            //FIXME: when can IllegalStateException be thrown?
+            // JmxAttributeValidationException is wrapped in DynamicWritableWrapper with ValidationException
+            // ValidationException is not thrown until validate or commit is issued
             logger.warn("Set phase for {} failed", EditConfigXmlParser.EDIT_CONFIG, e);
             final Map<String, String> errorInfo = new HashMap<>();
             errorInfo.put(ErrorTag.operation_failed.name(), e.getMessage());
@@ -101,7 +104,8 @@ public class EditConfig extends AbstractConfigNetconfOperation {
             EditConfigExecution editConfigExecution) throws NetconfDocumentedException {
         try {
             test(configRegistryClient, editConfigExecution, editConfigExecution.getDefaultStrategy());
-        } catch (IllegalStateException | JmxAttributeValidationException | ValidationException e) {
+        } catch (IllegalStateException | ValidationException e) {
+            //FIXME: when can IllegalStateException be thrown?
             logger.warn("Test phase for {} failed", EditConfigXmlParser.EDIT_CONFIG, e);
             final Map<String, String> errorInfo = new HashMap<>();
             errorInfo.put(ErrorTag.operation_failed.name(), e.getMessage());
@@ -112,7 +116,7 @@ public class EditConfig extends AbstractConfigNetconfOperation {
     }
 
     private void test(ConfigRegistryClient configRegistryClient, EditConfigExecution execution,
-            EditStrategyType editStrategyType) {
+            EditStrategyType editStrategyType) throws ValidationException {
         ObjectName taON = transactionProvider.getTestTransaction();
         try {
 
@@ -237,6 +241,7 @@ public class EditConfig extends AbstractConfigNetconfOperation {
             return identityNameToSchemaNode.containsKey(idName);
         }
 
+        // FIXME method never used
         public IdentitySchemaNode getIdentitySchemaNode(String idName) {
             Preconditions.checkState(identityNameToSchemaNode.containsKey(idName), "No identity under name %s", idName);
             return identityNameToSchemaNode.get(idName);
index 83029c44e665ec77bc5796535353277fe481ea43..5642cc7188788fd74a7aeccf7ca8ffa97abd009e 100644 (file)
@@ -25,7 +25,8 @@ public class Activator implements BundleActivator, YangStoreServiceTracker.YangS
     private static final Logger logger = LoggerFactory.getLogger(Activator.class);
 
     private BundleContext context;
-    ServiceRegistration osgiRegistration;
+    private ServiceRegistration osgiRegistration;
+    private ConfigRegistryLookupThread configRegistryLookup = null;
 
     @Override
     public void start(BundleContext context) throws Exception {
@@ -36,20 +37,42 @@ public class Activator implements BundleActivator, YangStoreServiceTracker.YangS
 
     @Override
     public void stop(BundleContext context) throws Exception {
+        if (configRegistryLookup != null) {
+            configRegistryLookup.interrupt();
+        }
     }
 
     @Override
     public synchronized void onYangStoreAdded(YangStoreService yangStoreService) {
-        checkState(osgiRegistration == null, "More than one onYangStoreAdded received");
-        NetconfOperationServiceFactoryImpl factory = new NetconfOperationServiceFactoryImpl(yangStoreService);
-        logger.debug("Registering into OSGi");
-        osgiRegistration = context.registerService(new String[]{NetconfOperationServiceFactory.class.getName()}, factory,
-                new Hashtable<String, Object>());
+        checkState(configRegistryLookup  == null, "More than one onYangStoreAdded received");
+        configRegistryLookup = new ConfigRegistryLookupThread(yangStoreService);
+        configRegistryLookup.start();
     }
 
     @Override
     public synchronized void onYangStoreRemoved() {
-        osgiRegistration.unregister();
+        configRegistryLookup.interrupt();
+        if (osgiRegistration != null) {
+            osgiRegistration.unregister();
+        }
         osgiRegistration = null;
+        configRegistryLookup = null;
+    }
+
+    private class ConfigRegistryLookupThread extends Thread {
+        private final YangStoreService yangStoreService;
+
+        private ConfigRegistryLookupThread(YangStoreService yangStoreService) {
+            super("config-registry-lookup");
+            this.yangStoreService = yangStoreService;
+        }
+
+        @Override
+        public void run() {
+            NetconfOperationServiceFactoryImpl factory = new NetconfOperationServiceFactoryImpl(yangStoreService);
+            logger.debug("Registering into OSGi");
+            osgiRegistration = context.registerService(new String[]{NetconfOperationServiceFactory.class.getName()}, factory,
+                    new Hashtable<String, Object>());
+        }
     }
 }
index cd3b44852c352cdf9ca905980790ae329e6143ba..d7cbf6680db5a06b311898f1464c99def0768dee 100644 (file)
@@ -10,11 +10,11 @@ package org.opendaylight.controller.netconf.confignetconfconnector.transactions;
 
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
+import org.opendaylight.controller.config.api.ConflictingVersionException;
 import org.opendaylight.controller.config.api.ValidationException;
 import org.opendaylight.controller.config.api.jmx.CommitStatus;
 import org.opendaylight.controller.config.util.ConfigRegistryClient;
 import org.opendaylight.controller.config.util.ConfigTransactionClient;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -94,7 +94,7 @@ public class TransactionProvider implements AutoCloseable {
     /**
      * Commit and notification send must be atomic
      */
-    public synchronized CommitStatus commitTransaction() throws NetconfDocumentedException {
+    public synchronized CommitStatus commitTransaction() throws ValidationException, ConflictingVersionException {
         final Optional<ObjectName> maybeTaON = getTransaction();
         Preconditions.checkState(maybeTaON.isPresent(), "No transaction found for session " + netconfSessionIdForReporting);
         ObjectName taON = maybeTaON.get();
@@ -108,7 +108,7 @@ public class TransactionProvider implements AutoCloseable {
             // no clean up: user can reconfigure and recover this transaction
             logger.warn("Transaction {} failed on {}", taON, validationException.toString());
             throw validationException;
-        } catch (Exception e) {
+        } catch (ConflictingVersionException e) {
             logger.error("Exception while commit of {}, aborting transaction", taON, e);
             // clean up
             abortTransaction();
@@ -142,7 +142,7 @@ public class TransactionProvider implements AutoCloseable {
         transactionClient.validateConfig();
     }
 
-    public void validateTestTransaction(ObjectName taON) {
+    public void validateTestTransaction(ObjectName taON) throws ValidationException {
         ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON);
         transactionClient.validateConfig();
     }
index 72d62efe84c21cfcf47e1c0d7ac8eb60bdbc97a7..0a4f82f057b72bb24dfc51b7d2c18df950b47483 100644 (file)
@@ -8,33 +8,11 @@
 
 package org.opendaylight.controller.netconf.confignetconfconnector;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.math.BigInteger;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.InstanceNotFoundException;
-import javax.management.ObjectName;
-import javax.xml.parsers.ParserConfigurationException;
-
+import com.google.common.base.Optional;
+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.apache.commons.lang3.StringUtils;
 import org.junit.Before;
 import org.junit.Ignore;
@@ -42,6 +20,8 @@ import org.junit.Test;
 import org.junit.matchers.JUnitMatchers;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.config.api.ValidationException;
 import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
 import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
 import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
@@ -92,11 +72,31 @@ import org.w3c.dom.Element;
 import org.w3c.dom.NodeList;
 import org.xml.sax.SAXException;
 
-import com.google.common.base.Optional;
-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 javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 
 
 public class NetconfMappingTest extends AbstractConfigTest {
@@ -130,7 +130,7 @@ public class NetconfMappingTest extends AbstractConfigTest {
         transactionProvider = new TransactionProvider(this.configRegistryClient, NETCONF_SESSION_ID);
     }
 
-    private ObjectName createModule(final String instanceName) throws InstanceAlreadyExistsException, InstanceNotFoundException, URISyntaxException {
+    private ObjectName createModule(final String instanceName) throws InstanceAlreadyExistsException, InstanceNotFoundException, URISyntaxException, ValidationException, ConflictingVersionException {
         final ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction();
 
         final ObjectName on = transaction.createModule(this.factory.getImplementationName(), instanceName);
index 505a91c6cec4ba7f4ce1139059538d322cf8ed69..b70a66f5efc7f8eb1a4d779bcb51ca2123d33227 100644 (file)
@@ -17,6 +17,7 @@ import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
+import org.opendaylight.controller.config.api.ValidationException;
 import org.opendaylight.controller.config.util.ConfigRegistryClient;
 import org.opendaylight.controller.config.util.ConfigTransactionClient;
 import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
@@ -79,7 +80,7 @@ public class EditConfigTest {
     }
 
     @Test
-    public void test() throws NetconfDocumentedException {
+    public void test() throws NetconfDocumentedException, ValidationException {
         EditConfig edit = new EditConfig(yangStoreSnapshot, provider, configRegistry,
                 ValidateTest.NETCONF_SESSION_ID_FOR_REPORTING);
         EditConfigStrategy editStrat = mock(EditConfigStrategy.class);
index 590381038a2cdd0bac29556a85a5fe9393e2330c..daaf60c1d3662caaa7a5febdb8da90f43eca4e46 100644 (file)
@@ -4,7 +4,7 @@
     <parent>
         <artifactId>netconf-subsystem</artifactId>
         <groupId>org.opendaylight.controller</groupId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
     </parent>
     <artifactId>config-persister-impl</artifactId>
     <name>${project.artifactId}</name>
         </dependency>
 
         <!-- test dependencies -->
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>netconf-impl</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>netconf-util</artifactId>
+            <scope>test</scope>
+            <type>test-jar</type>
+        </dependency>
         <dependency>
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>mockito-configuration</artifactId>
index 460aec6ac6fa94b4977c433ba3f6e76805bc8e8e..ea2a46dba535f825d0baa7b5dfa58d4b6371c297 100644 (file)
@@ -8,20 +8,7 @@
 
 package org.opendaylight.controller.netconf.persist.impl;
 
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.InetSocketAddress;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import javax.annotation.concurrent.Immutable;
-
+import com.google.common.base.Preconditions;
 import org.opendaylight.controller.config.api.ConflictingVersionException;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
@@ -38,35 +25,26 @@ import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.xml.sax.SAXException;
 
-import com.google.common.base.Preconditions;
-import io.netty.channel.EventLoopGroup;
+import javax.annotation.concurrent.Immutable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 @Immutable
 public class ConfigPusher {
     private static final Logger logger = LoggerFactory.getLogger(ConfigPusher.class);
-    private static final int NETCONF_SEND_ATTEMPT_MS_DELAY = 1000;
-    private static final int NETCONF_SEND_ATTEMPTS = 20;
-
-    private final InetSocketAddress address;
-    private final EventLoopGroup nettyThreadGroup;
-
-    // Default timeout for netconf becoming stable
-    public static final long DEFAULT_MAX_WAIT_FOR_CAPABILITIES_MILLIS = TimeUnit.MINUTES.toMillis(2);
-    public static final long DEFAULT_CONNECTION_TIMEOUT_MILLIS = 5000;
-    private final int delayMillis = 5000;
-    private final long maxWaitForCapabilitiesMillis;
-    private final long connectionTimeoutMillis;
 
-    public ConfigPusher(InetSocketAddress address, EventLoopGroup nettyThreadGroup) {
-        this(address, nettyThreadGroup, DEFAULT_MAX_WAIT_FOR_CAPABILITIES_MILLIS, DEFAULT_CONNECTION_TIMEOUT_MILLIS);
-    }
+    private final ConfigPusherConfiguration configuration;
 
-    public ConfigPusher(InetSocketAddress address, EventLoopGroup nettyThreadGroup,
-            long maxWaitForCapabilitiesMillis, long connectionTimeoutMillis) {
-        this.address = address;
-        this.nettyThreadGroup = nettyThreadGroup;
-        this.maxWaitForCapabilitiesMillis = maxWaitForCapabilitiesMillis;
-        this.connectionTimeoutMillis = connectionTimeoutMillis;
+    public ConfigPusher(ConfigPusherConfiguration configuration) {
+        this.configuration = configuration;
     }
 
     public synchronized LinkedHashMap<ConfigSnapshotHolder, EditAndCommitResponseWithRetries> pushConfigs(
@@ -97,7 +75,7 @@ public class ConfigPusher {
             throws InterruptedException {
 
         ConflictingVersionException lastException = null;
-        int maxAttempts = 30;
+        int maxAttempts = configuration.netconfPushConfigAttempts;
 
         for (int retryAttempt = 1; retryAttempt <= maxAttempts; retryAttempt++) {
             NetconfClient netconfClient = makeNetconfConnection(configSnapshotHolder.getCapabilities());
@@ -106,8 +84,9 @@ public class ConfigPusher {
                 EditAndCommitResponse editAndCommitResponse = pushLastConfig(configSnapshotHolder, netconfClient);
                 return new EditAndCommitResponseWithRetries(editAndCommitResponse, retryAttempt);
             } catch (ConflictingVersionException e) {
+                logger.debug("Conflicting version detected, will retry after timeout");
                 lastException = e;
-                Thread.sleep(1000);
+                Thread.sleep(configuration.netconfPushConfigDelayMs);
             } catch (RuntimeException e) {
                 throw new IllegalStateException("Unable to load " + configSnapshotHolder, e);
             } finally {
@@ -129,24 +108,25 @@ public class ConfigPusher {
         // could be utilized by integration tests
 
         final long pollingStartNanos = System.nanoTime();
-        final long deadlineNanos = pollingStartNanos + TimeUnit.MILLISECONDS.toNanos(maxWaitForCapabilitiesMillis);
+        final long deadlineNanos = pollingStartNanos + TimeUnit.MILLISECONDS.toNanos(configuration.netconfCapabilitiesWaitTimeoutMs);
         int attempt = 0;
 
-        NetconfHelloMessageAdditionalHeader additionalHeader = new NetconfHelloMessageAdditionalHeader("unknown", address.getAddress().getHostAddress(),
-                Integer.toString(address.getPort()), "tcp", "persister");
+        NetconfHelloMessageAdditionalHeader additionalHeader = new NetconfHelloMessageAdditionalHeader("unknown",
+                configuration.netconfAddress.getAddress().getHostAddress(),
+                Integer.toString(configuration.netconfAddress.getPort()), "tcp", "persister");
 
         Set<String> latestCapabilities = null;
         while (System.nanoTime() < deadlineNanos) {
             attempt++;
-            NetconfClientDispatcher netconfClientDispatcher = new NetconfClientDispatcher(nettyThreadGroup,
-                    nettyThreadGroup, additionalHeader, connectionTimeoutMillis);
+            NetconfClientDispatcher netconfClientDispatcher = new NetconfClientDispatcher(configuration.eventLoopGroup,
+                    configuration.eventLoopGroup, additionalHeader, configuration.connectionAttemptTimeoutMs);
             NetconfClient netconfClient;
             try {
-                netconfClient = new NetconfClient(this.toString(), address, delayMillis, netconfClientDispatcher);
+                netconfClient = new NetconfClient(this.toString(), configuration.netconfAddress, configuration.connectionAttemptDelayMs, netconfClientDispatcher);
             } catch (IllegalStateException e) {
-                logger.debug("Netconf {} was not initialized or is not stable, attempt {}", address, attempt, e);
+                logger.debug("Netconf {} was not initialized or is not stable, attempt {}", configuration.netconfAddress, attempt, e);
                 netconfClientDispatcher.close();
-                Thread.sleep(delayMillis);
+                Thread.sleep(configuration.connectionAttemptDelayMs);
                 continue;
             }
             latestCapabilities = netconfClient.getCapabilities();
@@ -155,21 +135,29 @@ public class ConfigPusher {
                 logger.trace("Session id received from netconf server: {}", netconfClient.getClientSession());
                 return netconfClient;
             }
-            logger.debug("Polling hello from netconf, attempt {}, capabilities {}", attempt, latestCapabilities);
+            Set<String> allNotFound = computeNotFoundCapabilities(expectedCaps, latestCapabilities);
+            logger.debug("Netconf server did not provide required capabilities. Attempt {}. " +
+                    "Expected but not found: {}, all expected {}, current {}",
+                    attempt, allNotFound, expectedCaps, latestCapabilities);
             Util.closeClientAndDispatcher(netconfClient);
-            Thread.sleep(delayMillis);
+            Thread.sleep(configuration.connectionAttemptDelayMs);
         }
         if (latestCapabilities == null) {
-            logger.error("Could not connect to the server in {} ms", maxWaitForCapabilitiesMillis);
+            logger.error("Could not connect to the server in {} ms", configuration.netconfCapabilitiesWaitTimeoutMs);
             throw new RuntimeException("Could not connect to netconf server");
         }
-        Set<String> allNotFound = new HashSet<>(expectedCaps);
-        allNotFound.removeAll(latestCapabilities);
+        Set<String> allNotFound = computeNotFoundCapabilities(expectedCaps, latestCapabilities);
         logger.error("Netconf server did not provide required capabilities. Expected but not found: {}, all expected {}, current {}",
                 allNotFound, expectedCaps, latestCapabilities);
         throw new RuntimeException("Netconf server did not provide required capabilities. Expected but not found:" + allNotFound);
     }
 
+    private static Set<String> computeNotFoundCapabilities(Set<String> expectedCaps, Set<String> latestCapabilities) {
+        Set<String> allNotFound = new HashSet<>(expectedCaps);
+        allNotFound.removeAll(latestCapabilities);
+        return allNotFound;
+    }
+
 
     /**
      * Sends two RPCs to the netconf server: edit-config and commit.
@@ -222,17 +210,23 @@ public class ConfigPusher {
     }
 
 
-    private static NetconfMessage sendRequestGetResponseCheckIsOK(NetconfMessage request, NetconfClient netconfClient) throws IOException {
+    private NetconfMessage sendRequestGetResponseCheckIsOK(NetconfMessage request, NetconfClient netconfClient)
+            throws ConflictingVersionException, IOException {
         try {
-            NetconfMessage netconfMessage = netconfClient.sendMessage(request, NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY);
+            NetconfMessage netconfMessage = netconfClient.sendMessage(request,
+                    configuration.netconfSendMessageMaxAttempts, configuration.netconfSendMessageDelayMs);
             NetconfUtil.checkIsMessageOk(netconfMessage);
             return netconfMessage;
-        } catch (RuntimeException | ExecutionException | InterruptedException | TimeoutException e) {
+        } catch(ConflictingVersionException e) {
+            logger.trace("conflicting version detected: {}", e.toString());
+            throw e;
+        } catch (RuntimeException | ExecutionException | InterruptedException | TimeoutException e) { // TODO: change NetconfClient#sendMessage to throw checked exceptions
             logger.debug("Error while executing netconf transaction {} to {}", request, netconfClient, e);
             throw new IOException("Failed to execute netconf transaction", e);
         }
     }
 
+
     // load editConfig.xml template, populate /rpc/edit-config/config with parameter
     private static NetconfMessage createEditConfigMessage(Element dataElement) {
         String editConfigResourcePath = "/netconfOp/editConfig.xml";
@@ -318,4 +312,5 @@ public class ConfigPusher {
                     '}';
         }
     }
+
 }
diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherConfiguration.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherConfiguration.java
new file mode 100644 (file)
index 0000000..aa189f0
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.netconf.persist.impl;
+
+import io.netty.channel.EventLoopGroup;
+
+import javax.annotation.concurrent.Immutable;
+import java.net.InetSocketAddress;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Configuration properties for ConfigPusher. Contains delays and timeouts for netconf
+ * connection establishment, netconf capabilities stabilization and configuration push.
+ */
+@Immutable
+public final class ConfigPusherConfiguration {
+
+    public static final long DEFAULT_CONNECTION_ATTEMPT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5);
+    public static final int DEFAULT_CONNECTION_ATTEMPT_DELAY_MS = 5000;
+
+    public static final int DEFAULT_NETCONF_SEND_MESSAGE_MAX_ATTEMPTS = 20;
+    public static final int DEFAULT_NETCONF_SEND_MESSAGE_DELAY_MS = 1000;
+
+    public static final long DEFAULT_NETCONF_CAPABILITIES_WAIT_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(2);
+
+    public static final int DEFAULT_NETCONF_PUSH_CONFIG_ATTEMPTS = 30;
+    public static final long DEFAULT_NETCONF_PUSH_CONFIG_DELAY_MS = TimeUnit.MINUTES.toMillis(1);
+
+    final InetSocketAddress netconfAddress;
+    final EventLoopGroup eventLoopGroup;
+
+    /**
+     * Total time to wait for capability stabilization
+     */
+    final long netconfCapabilitiesWaitTimeoutMs;
+
+    /**
+     * Delay between message send attempts
+     */
+    final int netconfSendMessageDelayMs;
+    /**
+     * Total number attempts to send a message
+     */
+    final int netconfSendMessageMaxAttempts;
+
+    /**
+     * Delay between connection establishment attempts
+     */
+    final int connectionAttemptDelayMs;
+    /**
+     * Total number of attempts to perform connection establishment
+     */
+    final long connectionAttemptTimeoutMs;
+
+    /**
+     * Total number of attempts to push configuration to netconf
+     */
+    final int netconfPushConfigAttempts;
+    /**
+     * Delay between configuration push attempts
+     */
+    final long netconfPushConfigDelayMs;
+
+    ConfigPusherConfiguration(InetSocketAddress netconfAddress, long netconfCapabilitiesWaitTimeoutMs,
+            int netconfSendMessageDelayMs, int netconfSendMessageMaxAttempts, int connectionAttemptDelayMs,
+            long connectionAttemptTimeoutMs, EventLoopGroup eventLoopGroup, int netconfPushConfigAttempts,
+            long netconfPushConfigDelayMs) {
+        this.netconfAddress = netconfAddress;
+        this.netconfCapabilitiesWaitTimeoutMs = netconfCapabilitiesWaitTimeoutMs;
+        this.netconfSendMessageDelayMs = netconfSendMessageDelayMs;
+        this.netconfSendMessageMaxAttempts = netconfSendMessageMaxAttempts;
+        this.connectionAttemptDelayMs = connectionAttemptDelayMs;
+        this.connectionAttemptTimeoutMs = connectionAttemptTimeoutMs;
+        this.eventLoopGroup = eventLoopGroup;
+        this.netconfPushConfigAttempts = netconfPushConfigAttempts;
+        this.netconfPushConfigDelayMs = netconfPushConfigDelayMs;
+    }
+}
diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherConfigurationBuilder.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherConfigurationBuilder.java
new file mode 100644 (file)
index 0000000..c26dc8d
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.netconf.persist.impl;
+
+import io.netty.channel.EventLoopGroup;
+
+import java.net.InetSocketAddress;
+
+public class ConfigPusherConfigurationBuilder {
+    InetSocketAddress netconfAddress;
+    EventLoopGroup eventLoopGroup;
+
+    long netconfCapabilitiesWaitTimeoutMs = ConfigPusherConfiguration.DEFAULT_NETCONF_CAPABILITIES_WAIT_TIMEOUT_MS;
+    int netconfSendMessageDelayMs = ConfigPusherConfiguration.DEFAULT_NETCONF_SEND_MESSAGE_DELAY_MS;
+    int netconfSendMessageMaxAttempts = ConfigPusherConfiguration.DEFAULT_NETCONF_SEND_MESSAGE_MAX_ATTEMPTS;
+    int connectionAttemptDelayMs = ConfigPusherConfiguration.DEFAULT_CONNECTION_ATTEMPT_DELAY_MS;
+    long connectionAttemptTimeoutMs = ConfigPusherConfiguration.DEFAULT_CONNECTION_ATTEMPT_TIMEOUT_MS;
+    int netconfPushConfigAttempts = ConfigPusherConfiguration.DEFAULT_NETCONF_PUSH_CONFIG_ATTEMPTS;
+    long netconfPushConfigDelayMs = ConfigPusherConfiguration.DEFAULT_NETCONF_PUSH_CONFIG_DELAY_MS;
+
+    private ConfigPusherConfigurationBuilder() {
+    }
+
+    public static ConfigPusherConfigurationBuilder aConfigPusherConfiguration() {
+        return new ConfigPusherConfigurationBuilder();
+    }
+
+    public ConfigPusherConfigurationBuilder withNetconfAddress(InetSocketAddress netconfAddress) {
+        this.netconfAddress = netconfAddress;
+        return this;
+    }
+
+    public ConfigPusherConfigurationBuilder withNetconfCapabilitiesWaitTimeoutMs(long netconfCapabilitiesWaitTimeoutMs) {
+        this.netconfCapabilitiesWaitTimeoutMs = netconfCapabilitiesWaitTimeoutMs;
+        return this;
+    }
+
+    public ConfigPusherConfigurationBuilder withNetconfSendMessageDelayMs(int netconfSendMessageDelayMs) {
+        this.netconfSendMessageDelayMs = netconfSendMessageDelayMs;
+        return this;
+    }
+
+    public ConfigPusherConfigurationBuilder withNetconfSendMessageMaxAttempts(int netconfSendMessageMaxAttempts) {
+        this.netconfSendMessageMaxAttempts = netconfSendMessageMaxAttempts;
+        return this;
+    }
+
+    public ConfigPusherConfigurationBuilder withConnectionAttemptDelayMs(int connectionAttemptDelayMs) {
+        this.connectionAttemptDelayMs = connectionAttemptDelayMs;
+        return this;
+    }
+
+    public ConfigPusherConfigurationBuilder withConnectionAttemptTimeoutMs(long connectionAttemptTimeoutMs) {
+        this.connectionAttemptTimeoutMs = connectionAttemptTimeoutMs;
+        return this;
+    }
+
+    public ConfigPusherConfigurationBuilder withEventLoopGroup(EventLoopGroup eventLoopGroup) {
+        this.eventLoopGroup = eventLoopGroup;
+        return this;
+    }
+
+    public ConfigPusherConfigurationBuilder withNetconfPushConfigAttempts(int netconfPushConfigAttempts) {
+        this.netconfPushConfigAttempts = netconfPushConfigAttempts;
+        return this;
+    }
+
+    public ConfigPusherConfigurationBuilder withNetconfPushConfigDelayMs(long netconfPushConfigDelayMs) {
+        this.netconfPushConfigDelayMs = netconfPushConfigDelayMs;
+        return this;
+    }
+
+    public ConfigPusherConfiguration build() {
+        ConfigPusherConfiguration configPusherConfiguration = new ConfigPusherConfiguration(netconfAddress,
+                netconfCapabilitiesWaitTimeoutMs, netconfSendMessageDelayMs, netconfSendMessageMaxAttempts,
+                connectionAttemptDelayMs, connectionAttemptTimeoutMs, eventLoopGroup, netconfPushConfigAttempts,
+                netconfPushConfigDelayMs);
+        return configPusherConfiguration;
+    }
+}
index f168bb36348103525b6895582d73c5c833b3eaed..c1cad4a8ddaba3750b70c3530d7f8324afde8a95 100644 (file)
@@ -134,7 +134,7 @@ public final class PersisterAggregator implements Persister {
     public static PersisterAggregator createFromProperties(PropertiesProviderBaseImpl propertiesProvider) {
         List<PersisterWithConfiguration> persisterWithConfigurations = new ArrayList<>();
         String prefixes = propertiesProvider.getProperty("active");
-        if (prefixes.isEmpty() == false) {
+        if (prefixes!=null && prefixes.isEmpty() == false) {
             String [] keys = prefixes.split(",");
             for (String index: keys) {
                 persisterWithConfigurations.add(PersisterAggregator.loadConfiguration(index, propertiesProvider));
index 1157ddbd83a814be6d7ea4091ea116bf8398255d..1246c78fbe21539589a23d641e58f4a1846da5c8 100644 (file)
@@ -8,10 +8,14 @@
 
 package org.opendaylight.controller.netconf.persist.impl.osgi;
 
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
 import io.netty.channel.EventLoopGroup;
 import io.netty.channel.nio.NioEventLoopGroup;
 import org.opendaylight.controller.netconf.persist.impl.ConfigPersisterNotificationHandler;
 import org.opendaylight.controller.netconf.persist.impl.ConfigPusher;
+import org.opendaylight.controller.netconf.persist.impl.ConfigPusherConfiguration;
+import org.opendaylight.controller.netconf.persist.impl.ConfigPusherConfigurationBuilder;
 import org.opendaylight.controller.netconf.persist.impl.PersisterAggregator;
 import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil;
 import org.osgi.framework.BundleActivator;
@@ -22,16 +26,16 @@ import org.slf4j.LoggerFactory;
 import javax.management.MBeanServer;
 import java.lang.management.ManagementFactory;
 import java.net.InetSocketAddress;
+import java.util.concurrent.ThreadFactory;
 import java.util.regex.Pattern;
 
 public class ConfigPersisterActivator implements BundleActivator {
 
     private static final Logger logger = LoggerFactory.getLogger(ConfigPersisterActivator.class);
 
-    private final static MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
-    private static final String IGNORED_MISSING_CAPABILITY_REGEX_SUFFIX = "ignoredMissingCapabilityRegex";
+    public static final String IGNORED_MISSING_CAPABILITY_REGEX_SUFFIX = "ignoredMissingCapabilityRegex";
 
-    private static final String MAX_WAIT_FOR_CAPABILITIES_MILLIS = "maxWaitForCapabilitiesMillis";
+    public static final String MAX_WAIT_FOR_CAPABILITIES_MILLIS = "maxWaitForCapabilitiesMillis";
 
     public static final String NETCONF_CONFIG_PERSISTER = "netconf.config.persister";
 
@@ -39,43 +43,43 @@ public class ConfigPersisterActivator implements BundleActivator {
 
     public static final String DEFAULT_IGNORED_REGEX = "^urn:ietf:params:xml:ns:netconf:base:1.0";
 
+    private final MBeanServer platformMBeanServer;
 
+    private final Optional<ConfigPusherConfiguration> initialConfigForPusher;
     private volatile ConfigPersisterNotificationHandler jmxNotificationHandler;
     private Thread initializationThread;
+    private ThreadFactory initializationThreadFactory;
     private EventLoopGroup nettyThreadGroup;
     private PersisterAggregator persisterAggregator;
 
+    public ConfigPersisterActivator() {
+        this(new ThreadFactory() {
+            @Override
+            public Thread newThread(Runnable initializationRunnable) {
+                return new Thread(initializationRunnable, "ConfigPersister-registrator");
+            }
+        }, ManagementFactory.getPlatformMBeanServer(), null);
+    }
+
+    @VisibleForTesting
+    protected ConfigPersisterActivator(ThreadFactory threadFactory, MBeanServer mBeanServer,
+            ConfigPusherConfiguration initialConfigForPusher) {
+        this.initializationThreadFactory = threadFactory;
+        this.platformMBeanServer = mBeanServer;
+        this.initialConfigForPusher = Optional.fromNullable(initialConfigForPusher);
+    }
+
     @Override
     public void start(final BundleContext context) throws Exception {
         logger.debug("ConfigPersister starting");
 
         PropertiesProviderBaseImpl propertiesProvider = new PropertiesProviderBaseImpl(context);
 
-        String regexProperty = propertiesProvider.getProperty(IGNORED_MISSING_CAPABILITY_REGEX_SUFFIX);
-        String regex;
-        if (regexProperty != null) {
-            regex = regexProperty;
-        } else {
-            regex = DEFAULT_IGNORED_REGEX;
-        }
-
-        String timeoutProperty = propertiesProvider.getProperty(MAX_WAIT_FOR_CAPABILITIES_MILLIS);
-        long maxWaitForCapabilitiesMillis;
-        if (timeoutProperty == null) {
-            maxWaitForCapabilitiesMillis = ConfigPusher.DEFAULT_MAX_WAIT_FOR_CAPABILITIES_MILLIS;
-        } else {
-            maxWaitForCapabilitiesMillis = Integer.valueOf(timeoutProperty);
-        }
-
-        final Pattern ignoredMissingCapabilityRegex = Pattern.compile(regex);
-        nettyThreadGroup = new NioEventLoopGroup();
+        final Pattern ignoredMissingCapabilityRegex = getIgnoredCapabilitiesProperty(propertiesProvider);
 
         persisterAggregator = PersisterAggregator.createFromProperties(propertiesProvider);
-        final InetSocketAddress address = NetconfConfigUtil.extractTCPNetconfAddress(context,
-                "Netconf is not configured, persister is not operational", true);
-        final ConfigPusher configPusher = new ConfigPusher(address, nettyThreadGroup, maxWaitForCapabilitiesMillis,
-                ConfigPusher.DEFAULT_CONNECTION_TIMEOUT_MILLIS);
 
+        final ConfigPusher configPusher = new ConfigPusher(getConfigurationForPusher(context, propertiesProvider));
 
         // offload initialization to another thread in order to stop blocking activator
         Runnable initializationRunnable = new Runnable() {
@@ -94,17 +98,59 @@ public class ConfigPersisterActivator implements BundleActivator {
                 logger.info("Configuration Persister initialization completed.");
             }
         };
-        initializationThread = new Thread(initializationRunnable, "ConfigPersister-registrator");
+
+        initializationThread = initializationThreadFactory.newThread(initializationRunnable);
         initializationThread.start();
     }
 
+    private Pattern getIgnoredCapabilitiesProperty(PropertiesProviderBaseImpl propertiesProvider) {
+        String regexProperty = propertiesProvider.getProperty(IGNORED_MISSING_CAPABILITY_REGEX_SUFFIX);
+        String regex;
+        if (regexProperty != null) {
+            regex = regexProperty;
+        } else {
+            regex = DEFAULT_IGNORED_REGEX;
+        }
+        return Pattern.compile(regex);
+    }
+
+    private Optional<Long> getMaxWaitForCapabilitiesProperty(PropertiesProviderBaseImpl propertiesProvider) {
+        String timeoutProperty = propertiesProvider.getProperty(MAX_WAIT_FOR_CAPABILITIES_MILLIS);
+        return Optional.fromNullable(timeoutProperty == null ? null : Long.valueOf(timeoutProperty));
+    }
+
+    private ConfigPusherConfiguration getConfigurationForPusher(BundleContext context,
+            PropertiesProviderBaseImpl propertiesProvider) {
+
+        // If configuration was injected via constructor, use it
+        if(initialConfigForPusher.isPresent())
+            return initialConfigForPusher.get();
+
+        Optional<Long> maxWaitForCapabilitiesMillis = getMaxWaitForCapabilitiesProperty(propertiesProvider);
+        final InetSocketAddress address = NetconfConfigUtil.extractTCPNetconfAddress(context,
+                "Netconf is not configured, persister is not operational", true);
+
+        nettyThreadGroup = new NioEventLoopGroup();
+
+        ConfigPusherConfigurationBuilder configPusherConfigurationBuilder = ConfigPusherConfigurationBuilder.aConfigPusherConfiguration();
+
+        if(maxWaitForCapabilitiesMillis.isPresent())
+            configPusherConfigurationBuilder.withNetconfCapabilitiesWaitTimeoutMs(maxWaitForCapabilitiesMillis.get());
+
+        return configPusherConfigurationBuilder
+                .withEventLoopGroup(nettyThreadGroup)
+                .withNetconfAddress(address)
+                .build();
+    }
+
     @Override
     public void stop(BundleContext context) throws Exception {
         initializationThread.interrupt();
         if (jmxNotificationHandler != null) {
             jmxNotificationHandler.close();
         }
-        nettyThreadGroup.shutdownGracefully();
+        if(nettyThreadGroup!=null)
+            nettyThreadGroup.shutdownGracefully();
         persisterAggregator.close();
     }
 }
diff --git a/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterTest.java b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterTest.java
new file mode 100644 (file)
index 0000000..230c747
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.netconf.persist.impl.osgi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import java.lang.management.ManagementFactory;
+import java.net.InetSocketAddress;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeoutException;
+
+import javax.management.MBeanServer;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.matchers.JUnitMatchers;
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
+import org.opendaylight.controller.netconf.persist.impl.ConfigPusherConfiguration;
+import org.opendaylight.controller.netconf.persist.impl.ConfigPusherConfigurationBuilder;
+
+import com.google.common.collect.Lists;
+import io.netty.channel.nio.NioEventLoopGroup;
+
+public class ConfigPersisterTest {
+
+    private MockedBundleContext ctx;
+    private ConfigPersisterActivator configPersisterActivator;
+    private static final MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
+
+    private static final String NETCONF_ADDRESS = "localhost";
+    private static final String NETCONF_PORT = "18383";
+    private static NioEventLoopGroup eventLoopGroup;
+
+    private void setUpContextAndStartPersister(Thread.UncaughtExceptionHandler exHandler, String requiredCapability, ConfigPusherConfiguration configuration)
+            throws Exception {
+        MockedBundleContext.DummyAdapterWithInitialSnapshot.expectedCapability = requiredCapability;
+        ctx = new MockedBundleContext(NETCONF_ADDRESS, NETCONF_PORT);
+        configPersisterActivator = new ConfigPersisterActivator(getThreadFactory(exHandler), mBeanServer,
+                configuration);
+        configPersisterActivator.start(ctx.getBundleContext());
+    }
+
+    @BeforeClass
+    public static void setUp() throws Exception {
+        eventLoopGroup = new NioEventLoopGroup();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        configPersisterActivator.stop(ctx.getBundleContext());
+    }
+
+    @AfterClass
+    public static void closeNettyGroup() throws Exception {
+        eventLoopGroup.shutdownGracefully();
+    }
+
+    @Test
+    public void testPersisterNetconfNotStarting() throws Exception {
+        final TestingExceptionHandler handler = new TestingExceptionHandler();
+
+        setUpContextAndStartPersister(handler, "cap2", getConfiguration(100, 100).build());
+
+        waitTestToFinish(2000);
+
+        handler.assertException("connect to netconf endpoint", RuntimeException.class,
+                "Could not connect to netconf server");
+    }
+
+    @Test
+    public void testPersisterNotAllCapabilitiesProvided() throws Exception {
+        final TestingExceptionHandler handler = new TestingExceptionHandler();
+        ConfigPusherConfiguration cfg = getConfiguration(500, 1000)
+                .withNetconfCapabilitiesWaitTimeoutMs(1000).build();
+
+        setUpContextAndStartPersister(handler, "required-cap", cfg);
+
+        try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1")) {
+
+            waitTestToFinish(2500);
+
+            handler.assertException("retrieve required capabilities from netconf endpoint", RuntimeException.class,
+                    "Expected but not found:[required-cap]");
+        }
+    }
+
+    @Test
+    public void testPersisterNoResponseFromNetconfAfterEdit() throws Exception {
+        final TestingExceptionHandler handler = new TestingExceptionHandler();
+        ConfigPusherConfiguration cfg = getConfigurationWithOnePushAttempt();
+
+        setUpContextAndStartPersister(handler, "cap1", cfg);
+
+        try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1")) {
+
+            waitTestToFinish(3000);
+
+            handler.assertException("receive response from netconf endpoint", IllegalStateException.class,
+                    "Unable to load", TimeoutException.class,
+                    null, 3);
+
+            assertEquals(1 + 2, endpoint.getReceivedMessages().size());
+            assertHelloMessage(endpoint.getReceivedMessages().get(1));
+            assertEditMessage(endpoint.getReceivedMessages().get(2));
+        }
+    }
+
+    private ConfigPusherConfiguration getConfigurationWithOnePushAttempt() {
+        return getConfiguration(500, 1000)
+                    .withNetconfCapabilitiesWaitTimeoutMs(1000)
+                    .withNetconfPushConfigAttempts(1)
+                    .withNetconfPushConfigDelayMs(100)
+                    .withNetconfSendMessageMaxAttempts(3)
+                    .withNetconfSendMessageDelayMs(500).build();
+    }
+
+    @Test
+    public void testPersisterSuccessfulPush() throws Exception {
+        final TestingExceptionHandler handler = new TestingExceptionHandler();
+        ConfigPusherConfiguration cfg = getConfigurationForSuccess();
+
+        setUpContextAndStartPersister(handler, "cap1", cfg);
+
+        try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1", MockNetconfEndpoint.okMessage,
+                MockNetconfEndpoint.okMessage)) {
+
+            waitTestToFinish(4000);
+
+            handler.assertException("register as JMX listener", RuntimeException.class,
+                    "Cannot register as JMX listener to netconf");
+
+            assertEquals(1 + 3, endpoint.getReceivedMessages().size());
+            assertCommitMessage(endpoint.getReceivedMessages().get(3));
+        }
+    }
+
+    private ConfigPusherConfiguration getConfigurationForSuccess() {
+        return getConfiguration(500, 1000)
+                    .withNetconfCapabilitiesWaitTimeoutMs(1000)
+                    .withNetconfPushConfigAttempts(3)
+                    .withNetconfPushConfigDelayMs(100)
+                    .withNetconfSendMessageMaxAttempts(3)
+                    .withNetconfSendMessageDelayMs(500).build();
+    }
+
+    @Test
+    public void testPersisterConflictingVersionException() throws Exception {
+        final TestingExceptionHandler handler = new TestingExceptionHandler();
+        ConfigPusherConfiguration cfg = getConfigurationWithOnePushAttempt();
+
+        setUpContextAndStartPersister(handler, "cap1", cfg);
+
+        try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1", MockNetconfEndpoint.okMessage,
+                MockNetconfEndpoint.conflictingVersionErrorMessage); DefaultCommitNotificationProducer jMXNotifier = startJMXCommitNotifier();) {
+
+            Thread.sleep(4000);
+
+            handler.assertException("register as JMX listener", IllegalStateException.class,
+                    "Maximum attempt count has been reached for pushing", ConflictingVersionException.class, "Optimistic lock failed", 1);
+
+            assertEquals(1 + 3, endpoint.getReceivedMessages().size());
+            assertCommitMessage(endpoint.getReceivedMessages().get(3));
+        }
+    }
+
+    @Test
+    public void testPersisterConflictingVersionExceptionThenSuccess() throws Exception {
+        final TestingExceptionHandler handler = new TestingExceptionHandler();
+        ConfigPusherConfiguration cfg = getConfigurationForSuccess();
+
+        setUpContextAndStartPersister(handler, "cap1", cfg);
+
+        MockNetconfEndpoint.MessageSequence conflictingMessageSequence = new MockNetconfEndpoint.MessageSequence(
+                MockNetconfEndpoint.okMessage, MockNetconfEndpoint.conflictingVersionErrorMessage);
+        MockNetconfEndpoint.MessageSequence okMessageSequence = new MockNetconfEndpoint.MessageSequence(
+                MockNetconfEndpoint.okMessage, MockNetconfEndpoint.okMessage);
+
+        try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1",
+                Lists.newArrayList(conflictingMessageSequence, okMessageSequence));
+             DefaultCommitNotificationProducer jMXNotifier = startJMXCommitNotifier()) {
+
+            Thread.sleep(4000);
+
+            handler.assertNoException();
+
+            assertEquals(1 + 3/*Hello + Edit + Commit*/ + 3/*Hello + Edit + Commit*/, endpoint.getReceivedMessages().size());
+            assertCommitMessage(endpoint.getReceivedMessages().get(6));
+        }
+    }
+
+    @Test
+    public void testPersisterSuccessfulPushAndSuccessfulJMXRegistration() throws Exception {
+        final TestingExceptionHandler handler = new TestingExceptionHandler();
+        ConfigPusherConfiguration cfg = getConfigurationForSuccess();
+
+        setUpContextAndStartPersister(handler, "cap1", cfg);
+
+        try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1", MockNetconfEndpoint.okMessage,
+                MockNetconfEndpoint.okMessage); DefaultCommitNotificationProducer jMXNotifier = startJMXCommitNotifier()) {
+
+            Thread.sleep(2000);
+
+            handler.assertNoException();
+
+            assertEquals(1 + 3, endpoint.getReceivedMessages().size());
+        }
+    }
+
+    private ConfigPusherConfigurationBuilder getConfiguration(int connectionAttemptDelayMs, int connectionAttemptTimeoutMs) {
+        return ConfigPusherConfigurationBuilder.aConfigPusherConfiguration()
+                .withEventLoopGroup(eventLoopGroup)
+                .withConnectionAttemptDelayMs(connectionAttemptDelayMs)
+                .withConnectionAttemptTimeoutMs(connectionAttemptTimeoutMs)
+                .withNetconfCapabilitiesWaitTimeoutMs(44)
+                .withNetconfAddress(new InetSocketAddress(NETCONF_ADDRESS, Integer.valueOf(NETCONF_PORT)));
+    }
+
+    private void waitTestToFinish(int i) throws InterruptedException {
+        Thread.sleep(i);
+    }
+
+
+    private DefaultCommitNotificationProducer startJMXCommitNotifier() {
+        return new DefaultCommitNotificationProducer(mBeanServer);
+    }
+
+    private void assertEditMessage(String netconfMessage) {
+        assertThat(netconfMessage,
+                JUnitMatchers.containsString(MockedBundleContext.DummyAdapterWithInitialSnapshot.CONFIG_SNAPSHOT));
+    }
+
+    private void assertCommitMessage(String netconfMessage) {
+        assertThat(netconfMessage, JUnitMatchers.containsString("<commit"));
+    }
+
+    private void assertHelloMessage(String netconfMessage) {
+        assertThat(netconfMessage,
+                JUnitMatchers.containsString("<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"));
+        assertThat(netconfMessage, JUnitMatchers.containsString("<capability>"));
+    }
+
+    private MockNetconfEndpoint startMockNetconfEndpoint(String capability, List<MockNetconfEndpoint.MessageSequence> messageSequences) {
+        // Add first empty sequence for testing connection created by config persister at startup
+        messageSequences.add(0, new MockNetconfEndpoint.MessageSequence(Collections.<String>emptyList()));
+        return new MockNetconfEndpoint(capability, NETCONF_PORT, messageSequences);
+    }
+
+    private MockNetconfEndpoint startMockNetconfEndpoint(String capability, String... messages) {
+        return startMockNetconfEndpoint(capability, Lists.newArrayList(new MockNetconfEndpoint.MessageSequence(messages)));
+    }
+
+    public ThreadFactory getThreadFactory(final Thread.UncaughtExceptionHandler exHandler) {
+        return new ThreadFactory() {
+            @Override
+            public Thread newThread(Runnable r) {
+                Thread thread = new Thread(r, "config-persister-testing-activator");
+                thread.setUncaughtExceptionHandler(exHandler);
+                return thread;
+            }
+        };
+    }
+}
diff --git a/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/MockNetconfEndpoint.java b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/MockNetconfEndpoint.java
new file mode 100644 (file)
index 0000000..913db28
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.netconf.persist.impl.osgi;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketTimeoutException;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+
+import com.google.common.collect.Lists;
+
+class MockNetconfEndpoint implements AutoCloseable {
+
+    public static final int READ_SOCKET_TIMEOUT = 3000;
+
+    public static final String MSG_SEPARATOR = "]]>]]>\n";
+
+    private final AtomicBoolean stopped = new AtomicBoolean(false);
+    private List<String> receivedMessages = Lists.newCopyOnWriteArrayList();
+    private Thread innerThread;
+
+    MockNetconfEndpoint(String capability, String netconfPort, List<MessageSequence> messageSequence) {
+        helloMessage = helloMessage.replace("capability_place_holder", capability);
+        start(netconfPort, messageSequence);
+    }
+
+    private String helloMessage = "<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" +
+            "<capabilities>\n" +
+            "<capability>capability_place_holder</capability>\n" +
+            "</capabilities>\n" +
+            "<session-id>1</session-id>\n" +
+            "</hello>\n" +
+            MSG_SEPARATOR;
+
+    public static String conflictingVersionErrorMessage;
+    static {
+        try {
+            conflictingVersionErrorMessage = XmlUtil.toString(XmlFileLoader
+                    .xmlFileToDocument("netconfMessages/conflictingversion/conflictingVersionResponse.xml")) + MSG_SEPARATOR;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static String okMessage = "<rpc-reply message-id=\"1\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" +
+            "<ok/>\n" +
+            "</rpc-reply>" +
+            MSG_SEPARATOR ;
+
+    private void start(final String port, final List<MessageSequence> messagesToSend) {
+        innerThread = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                int clientCounter = 0;
+
+                while (stopped.get() == false) {
+                    try (ServerSocket s = new ServerSocket(Integer.valueOf(port))) {
+                        s.setSoTimeout(READ_SOCKET_TIMEOUT);
+
+                        Socket clientSocket = s.accept();
+                        clientCounter++;
+                        clientSocket.setSoTimeout(READ_SOCKET_TIMEOUT);
+
+                        PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
+                        BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
+
+                        // Negotiate
+                        sendMessage(out, helloMessage);
+                        receiveMessage(in);
+
+                        // Accept next message (edit-config)
+                        receiveMessage(in);
+
+                        for (String message : getMessageSequenceForClient(messagesToSend, clientCounter)) {
+                            sendMessage(out, message);
+                            receiveMessage(in);
+                        }
+                    } catch (SocketTimeoutException e) {
+                        // No more activity on netconf endpoint, close
+                        return;
+                    } catch (Exception e) {
+                        throw new RuntimeException(e);
+                    }
+                }
+            }
+
+            private Iterable<? extends String> getMessageSequenceForClient(List<MessageSequence> messagesToSend,
+                    int clientCounter) {
+                if (messagesToSend.size() <= clientCounter) {
+                    return messagesToSend.get(messagesToSend.size() - 1).getMessages();
+                } else {
+                    return messagesToSend.get(clientCounter - 1).getMessages();
+                }
+            }
+
+            private void receiveMessage(BufferedReader in) throws Exception {
+                String message = readMessage(in);
+                if(message == null || message.equals(""))
+                    return;
+                receivedMessages.add(message);
+            }
+
+            private String readMessage(BufferedReader in) throws IOException {
+                int c;
+                StringBuilder b = new StringBuilder();
+
+                while((c = in.read()) != -1) {
+                    b.append((char)c);
+                    if(b.toString().endsWith("]]>]]>"))
+                        break;
+                }
+
+                return b.toString();
+            }
+
+            private void sendMessage(PrintWriter out, String message) throws InterruptedException {
+                out.print(message);
+                out.flush();
+            }
+
+        });
+        innerThread.setName("Mocked-netconf-endpoint-inner-thread");
+        innerThread.start();
+    }
+
+    public List<String> getReceivedMessages() {
+        return receivedMessages;
+    }
+
+    public void close() throws IOException, InterruptedException {
+        stopped.set(true);
+        innerThread.join();
+    }
+
+    static class MessageSequence {
+        private List<String> messages;
+
+        MessageSequence(List<String> messages) {
+            this.messages = messages;
+        }
+
+        MessageSequence(String... messages) {
+            this(Lists.newArrayList(messages));
+        }
+
+        public Collection<String> getMessages() {
+            return messages;
+        }
+    }
+}
diff --git a/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/MockedBundleContext.java b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/MockedBundleContext.java
new file mode 100644 (file)
index 0000000..97cf7ec
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.netconf.persist.impl.osgi;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+import org.opendaylight.controller.config.persist.api.Persister;
+import org.opendaylight.controller.config.persist.api.PropertiesProvider;
+import org.opendaylight.controller.netconf.persist.impl.DummyAdapter;
+import org.osgi.framework.BundleContext;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import static org.mockito.Mockito.doReturn;
+
+final class MockedBundleContext {
+
+    @Mock
+    private BundleContext context;
+
+    MockedBundleContext(String netconfAddress, String netconfPort) {
+        MockitoAnnotations.initMocks(this);
+        initContext(netconfAddress, netconfPort);
+    }
+
+    public BundleContext getBundleContext() {
+        return context;
+    }
+
+    private void initContext(String netconfAddress, String netconfPort) {
+        initProp(context, ConfigPersisterActivator.IGNORED_MISSING_CAPABILITY_REGEX_SUFFIX, null);
+
+        initPropNoPrefix(context, "netconf.tcp.client.address", netconfAddress);
+        initPropNoPrefix(context, "netconf.tcp.client.port", netconfPort);
+
+        initProp(context, "active", "1");
+        initProp(context, "1." + ConfigPersisterActivator.STORAGE_ADAPTER_CLASS_PROP_SUFFIX, DummyAdapterWithInitialSnapshot.class.getName());
+        initProp(context, "1." + "readonly", "false");
+        initProp(context, "1." + ".properties.fileStorage", "target/configuration-persister-test/initial/");
+
+    }
+
+    private void initProp(BundleContext context, String key, String value) {
+        initPropNoPrefix(context, ConfigPersisterActivator.NETCONF_CONFIG_PERSISTER + "." + key, value);
+    }
+
+    private void initPropNoPrefix(BundleContext context, String key, String value) {
+        doReturn(value).when(context).getProperty(key);
+    }
+
+    public static class DummyAdapterWithInitialSnapshot extends DummyAdapter {
+
+        public static final String CONFIG_SNAPSHOT = "config-snapshot";
+        public static String expectedCapability = "cap2";
+
+        @Override
+        public List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
+            return Lists.newArrayList(getConfigSnapshopt());
+        }
+
+        @Override
+        public Persister instantiate(PropertiesProvider propertiesProvider) {
+            return this;
+        }
+
+        public ConfigSnapshotHolder getConfigSnapshopt() {
+            return new ConfigSnapshotHolder() {
+                @Override
+                public String getConfigSnapshot() {
+                    return "<data><" + CONFIG_SNAPSHOT + "/></data>";
+                }
+
+                @Override
+                public SortedSet<String> getCapabilities() {
+                    TreeSet<String> strings = Sets.newTreeSet();
+                    strings.add(expectedCapability);
+                    return strings;
+                }
+
+                @Override
+                public String toString() {
+                    return getConfigSnapshot();
+                }
+            };
+        }
+    }
+}
diff --git a/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/TestingExceptionHandler.java b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/TestingExceptionHandler.java
new file mode 100644 (file)
index 0000000..d42c15b
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.netconf.persist.impl.osgi;
+
+import org.junit.matchers.JUnitMatchers;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+
+final class TestingExceptionHandler implements Thread.UncaughtExceptionHandler {
+
+    private Throwable t;
+
+    @Override
+    public void uncaughtException(Thread t, Throwable e) {
+        this.t = e;
+    }
+
+    public void assertException(String failMessageSuffix, Class<? extends Exception> exType, String exMessageToContain) {
+        if(t == null) {
+            fail("Should fail to " + failMessageSuffix);
+        }
+        else {
+            assertException(t, exType, exMessageToContain);
+        }
+    }
+
+    public void assertNoException() {
+        assertNull("No exception expected but was " + t, t);
+    }
+
+    private void assertException(Throwable t, Class<? extends Exception> exType, String exMessageToContain) {
+        assertEquals("Expected exception of type " + exType + " but was " + t, exType, t.getClass());
+        if(exMessageToContain!=null) {
+            assertThat(t.getMessage(), JUnitMatchers.containsString(exMessageToContain));
+        }
+    }
+
+    public void assertException(String failMessageSuffix, Class<? extends Exception> exType,
+            String exMessageToContain, Class<? extends Exception> nestedExType, String nestedExMessageToContain,
+            int nestedExDepth) {
+        assertException(failMessageSuffix, exType, exMessageToContain);
+        assertNotNull("Expected nested exception in " + t, t.getCause());
+        assertException(getNestedException(t, nestedExDepth), nestedExType, nestedExMessageToContain);
+    }
+
+    private Throwable getNestedException(Throwable t, int nestedExDepth) {
+
+        int depth = 0;
+        while(t.getCause() != null) {
+            t = t.getCause();
+            depth++;
+            if(nestedExDepth == depth)
+                return t;
+        }
+        throw new IllegalArgumentException("Unable to get nested exception from " + t + " from depth " + nestedExDepth);
+    }
+}
index c6111ab3952f443d5efdd822e7e15e39644e9274..7b872db9a66a72dd89da334533f15916cf25d93c 100644 (file)
@@ -2,7 +2,7 @@
     <parent>
         <artifactId>netconf-subsystem</artifactId>
         <groupId>org.opendaylight.controller</groupId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>ietf-netconf-monitoring-extension</artifactId>
index e6a186c8810249f413b9742f2f80ecc144871481..f1e5764ca6bf5983fae7aa69cd3749b2878e481b 100644 (file)
@@ -3,7 +3,7 @@
     <parent>
         <artifactId>netconf-subsystem</artifactId>
         <groupId>org.opendaylight.controller</groupId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>ietf-netconf-monitoring</artifactId>
index 971f4a7bb44aad8941f1890aebba69f88b8ca871..3b5ed82518948fc21c6c4891b7a5ac85ecfa6f0b 100644 (file)
@@ -4,7 +4,7 @@
     <parent>
         <artifactId>netconf-subsystem</artifactId>
         <groupId>org.opendaylight.controller</groupId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>netconf-api</artifactId>
@@ -50,6 +50,7 @@
                         </Private-Package>
                         <Import-Package>
                             javax.management,
+                            org.opendaylight.controller.config.api,
                             org.opendaylight.controller.config.api.jmx,
                             org.opendaylight.protocol.framework,
                             io.netty.channel,
index 5a85e9425783c4171ce41d52b01dd71b9a3c9079..ceeca51defdff65016a842faaa97bfcdc165d6ae 100644 (file)
@@ -8,7 +8,11 @@
 
 package org.opendaylight.controller.netconf.api;
 
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.config.api.ValidationException;
+
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.Map;
 
 /**
@@ -19,6 +23,8 @@ public class NetconfDocumentedException extends Exception {
 
     private static final long serialVersionUID = 1L;
 
+
+
     public enum ErrorType {
         transport, rpc, protocol, application;
 
@@ -84,6 +90,20 @@ public class NetconfDocumentedException extends Exception {
         this.errorInfo = errorInfo;
     }
 
+    public static NetconfDocumentedException wrap(ValidationException e) throws NetconfDocumentedException {
+        final Map<String, String> errorInfo = new HashMap<>();
+        errorInfo.put(ErrorTag.operation_failed.name(), "Validation failed");
+        throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.application, ErrorTag.operation_failed,
+                ErrorSeverity.error, errorInfo);
+    }
+
+    public static NetconfDocumentedException wrap(ConflictingVersionException e) throws NetconfDocumentedException {
+        final Map<String, String> errorInfo = new HashMap<>();
+        errorInfo.put(ErrorTag.operation_failed.name(), "Optimistic lock failed");
+        throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.application, ErrorTag.operation_failed,
+                ErrorSeverity.error, errorInfo);
+    }
+
     public ErrorType getErrorType() {
         return this.errorType;
     }
index e6cba9258e8b70a5ec7ce1a92286efdb9bdf957e..b0f5f748106ab499ab95983cbb358f84536dbd66 100644 (file)
@@ -4,7 +4,7 @@
     <parent>
         <artifactId>netconf-subsystem</artifactId>
         <groupId>org.opendaylight.controller</groupId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
     </parent>
     <artifactId>netconf-client</artifactId>
     <name>${project.artifactId}</name>
index f4fc1ff0d5d62d7b8bf2f27bc2cd121f57fc86cf..85fff89777e9caf5c8a10aab4f5c09a57c15dc0d 100644 (file)
@@ -4,7 +4,7 @@
     <parent>
         <artifactId>netconf-subsystem</artifactId>
         <groupId>org.opendaylight.controller</groupId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>netconf-impl</artifactId>
index 9b0c7ab08a29ef028563f5dd254c931ae7605a25..57067f47ecded6b0d9e6bd745b0b0de3df344d3d 100644 (file)
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>netconf-subsystem</artifactId>
         <groupId>org.opendaylight.controller</groupId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
     </parent>
 
     <artifactId>netconf-it</artifactId>
             <artifactId>yang-store-api</artifactId>
             <scope>test</scope>
         </dependency>
-        <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>yang-test</artifactId>
-            <scope>test</scope>
-        </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>netconf-api</artifactId>
             <artifactId>netconf-monitoring</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>sal-binding-it</artifactId>
+            <version>${mdsal.version}</version>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>netconf-mapping-api</artifactId>
             <scope>test</scope>
             <type>test-jar</type>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>yang-test</artifactId>
+            <version>${config.version}</version>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>yang-store-impl</artifactId>
                     </execution>
                 </executions>
             </plugin>
+            <plugin>
+                <groupId>org.ops4j.pax.exam</groupId>
+                <artifactId>maven-paxexam-plugin</artifactId>
+                <version>1.2.4</version>
+                <executions>
+                    <execution>
+                        <id>generate-config</id>
+                        <goals>
+                            <goal>generate-depends-file</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
         </plugins>
     </build>
 </project>
diff --git a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/pax/IdentityRefNetconfTest.java b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/pax/IdentityRefNetconfTest.java
new file mode 100644 (file)
index 0000000..4e536c4
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.netconf.it.pax;
+
+import static org.opendaylight.controller.test.sal.binding.it.TestHelper.baseModelBundles;
+import static org.opendaylight.controller.test.sal.binding.it.TestHelper.bindingAwareSalBundles;
+import static org.opendaylight.controller.test.sal.binding.it.TestHelper.configMinumumBundles;
+import static org.opendaylight.controller.test.sal.binding.it.TestHelper.flowCapableModelBundles;
+import static org.opendaylight.controller.test.sal.binding.it.TestHelper.junitAndMockitoBundles;
+import static org.opendaylight.controller.test.sal.binding.it.TestHelper.mdSalCoreBundles;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+
+import javax.inject.Inject;
+import javax.xml.parsers.ParserConfigurationException;
+
+import com.google.common.base.Preconditions;
+import io.netty.channel.nio.NioEventLoopGroup;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.matchers.JUnitMatchers;
+import org.junit.runner.RunWith;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.client.NetconfClient;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.options.DefaultCompositeOption;
+import org.ops4j.pax.exam.util.Filter;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetSocketAddress;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+
+@RunWith(PaxExam.class)
+public class IdentityRefNetconfTest {
+
+    public static final int CLIENT_CONNECTION_TIMEOUT_MILLIS = 5000;
+
+    // Wait for controller to start
+    @Inject
+    @Filter(timeout = 60 * 1000)
+    BindingAwareBroker broker;
+
+    @Configuration
+    public Option[] config() {
+        return options(
+                systemProperty("osgi.console").value("2401"),
+                systemProperty("osgi.bundles.defaultStartLevel").value("4"),
+                systemProperty("pax.exam.osgi.unresolved.fail").value("true"),
+
+                testingModules(),
+                loggingModules(),
+                mdSalCoreBundles(),
+                bindingAwareSalBundles(), configMinumumBundles(), baseModelBundles(), flowCapableModelBundles(),
+                junitAndMockitoBundles());
+    }
+
+    private Option loggingModules() {
+        return new DefaultCompositeOption(
+                mavenBundle("org.slf4j", "slf4j-api").versionAsInProject(),
+                mavenBundle("org.slf4j", "log4j-over-slf4j").versionAsInProject(),
+                mavenBundle("ch.qos.logback", "logback-core").versionAsInProject(),
+                mavenBundle("ch.qos.logback", "logback-classic").versionAsInProject());
+    }
+
+    private Option testingModules() {
+        return new DefaultCompositeOption(
+                mavenBundle("org.opendaylight.controller", "yang-test").versionAsInProject());
+    }
+
+    private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 18383);
+
+    @Test
+    public void testIdRef() throws Exception {
+        Preconditions.checkNotNull(broker, "Controller not initialized");
+
+        NioEventLoopGroup nettyThreadgroup = new NioEventLoopGroup();
+        NetconfClientDispatcher clientDispatcher = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup,
+                CLIENT_CONNECTION_TIMEOUT_MILLIS);
+
+        NetconfMessage edit = xmlFileToNetconfMessage("netconfMessages/editConfig_identities.xml");
+        NetconfMessage commit = xmlFileToNetconfMessage("netconfMessages/commit.xml");
+        NetconfMessage getConfig = xmlFileToNetconfMessage("netconfMessages/getConfig.xml");
+
+        try (NetconfClient netconfClient = new NetconfClient("client", tcpAddress, CLIENT_CONNECTION_TIMEOUT_MILLIS, clientDispatcher)) {
+            sendMessage(edit, netconfClient);
+            sendMessage(commit, netconfClient);
+            sendMessage(getConfig, netconfClient, "id-test",
+                    "<afi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity1</afi>",
+                    "<afi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity2</afi>",
+                    "<safi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity2</safi>",
+                    "<safi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity1</safi>");
+        }
+
+        clientDispatcher.close();
+    }
+
+    private void sendMessage(NetconfMessage edit, NetconfClient netconfClient, String... containingResponse)
+            throws ExecutionException, InterruptedException, TimeoutException {
+        NetconfMessage response = netconfClient.sendRequest(edit).get();
+        if (containingResponse == null) {
+            Assert.assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("<ok/>"));
+        } else {
+            for (String resp : containingResponse) {
+                Assert.assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString(resp));
+            }
+        }
+    }
+
+    public static NetconfMessage xmlFileToNetconfMessage(final String fileName) throws IOException, SAXException,
+            ParserConfigurationException {
+        return new NetconfMessage(xmlFileToDocument(fileName));
+    }
+
+    public static Document xmlFileToDocument(final String fileName) throws IOException, SAXException,
+            ParserConfigurationException {
+        // TODO xml messages from netconf-util test-jar cannot be loaded here(in OSGi), since test jar is not a bundle
+        try (InputStream resourceAsStream = IdentityRefNetconfTest.class.getClassLoader().getResourceAsStream(fileName)) {
+            Preconditions.checkNotNull(resourceAsStream);
+            final Document doc = XmlUtil.readXmlToDocument(resourceAsStream);
+            return doc;
+        }
+    }
+}
diff --git a/opendaylight/netconf/netconf-it/src/test/resources/controller.xml b/opendaylight/netconf/netconf-it/src/test/resources/controller.xml
new file mode 100644 (file)
index 0000000..664a30d
--- /dev/null
@@ -0,0 +1,181 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<persisted-snapshots>
+   <snapshots>
+      <snapshot>
+         <required-capabilities>
+            <capability>urn:opendaylight:params:xml:ns:yang:controller:config:test:types?module=test-types&amp;revision=2013-11-27</capability>
+            <capability>urn:opendaylight:params:xml:ns:yang:controller:config?module=config&amp;revision=2013-04-05</capability>
+            <capability>urn:opendaylight:params:xml:ns:yang:controller:logback:config?module=config-logging&amp;revision=2013-07-16</capability>
+            <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&amp;revision=2013-10-28</capability>
+            <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&amp;revision=2013-10-28</capability>
+            <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&amp;revision=2013-10-28</capability>
+            <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom?module=opendaylight-md-sal-dom&amp;revision=2013-10-28</capability>
+            <capability>urn:opendaylight:params:xml:ns:yang:controller:test:impl?module=config-test-impl&amp;revision=2013-04-03</capability>
+            <capability>urn:opendaylight:params:xml:ns:yang:controller:test?module=config-test&amp;revision=2013-06-13</capability>
+         </required-capabilities>
+         <configuration>
+            <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+               <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+                  <module>
+                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test:impl">prefix:impl-identity-test</type>
+                     <name>id-test</name>
+                     <identities-container xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+                        <afi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:test:types">prefix:test-identity2</afi>
+                     </identities-container>
+                     <identities xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+                        <safi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:test:types">prefix:test-identity2</safi>
+                        <afi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:test:types">prefix:test-identity1</afi>
+                     </identities>
+                     <identities xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+                        <safi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:test:types">prefix:test-identity1</safi>
+                        <afi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:test:types">prefix:test-identity2</afi>
+                     </identities>
+                     <afi xmlns="urn:opendaylight:params:xml:ns:yang:controller:test:impl" xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:test:types">prefix:test-identity1</afi>
+                  </module>
+                  <module>
+                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-broker-impl</type>
+                     <name>binding-broker-impl</name>
+                     <notification-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                        <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-notification-service</type>
+                        <name>ref_binding-notification-broker</name>
+                     </notification-service>
+                     <data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                        <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-data-broker</type>
+                        <name>ref_binding-data-broker</name>
+                     </data-broker>
+                  </module>
+                  <module>
+                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:runtime-generated-mapping</type>
+                     <name>runtime-mapping-singleton</name>
+                  </module>
+                  <module>
+                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-notification-broker</type>
+                     <name>binding-notification-broker</name>
+                  </module>
+                  <module>
+                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-data-broker</type>
+                     <name>binding-data-broker</name>
+                     <dom-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                        <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">prefix:dom-broker-osgi-registry</type>
+                        <name>ref_dom-broker</name>
+                     </dom-broker>
+                     <mapping-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                        <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-dom-mapping-service</type>
+                        <name>ref_runtime-mapping-singleton</name>
+                     </mapping-service>
+                  </module>
+                  <module>
+                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:logback:config">prefix:logback</type>
+                     <name>singleton</name>
+                     <console-appenders xmlns="urn:opendaylight:params:xml:ns:yang:controller:logback:config">
+                        <threshold-filter>DEBUG</threshold-filter>
+                        <name>console</name>
+                        <encoder-pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</encoder-pattern>
+                     </console-appenders>
+                     <loggers xmlns="urn:opendaylight:params:xml:ns:yang:controller:logback:config">
+                        <level>DEBUG</level>
+                        <logger-name>ROOT</logger-name>
+                        <appenders>console</appenders>
+                     </loggers>
+                  </module>
+                  <module>
+                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:schema-service-singleton</type>
+                     <name>yang-schema-service</name>
+                  </module>
+                  <module>
+                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:hash-map-data-store</type>
+                     <name>hash-map-data-store</name>
+                  </module>
+                  <module>
+                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-broker-impl</type>
+                     <name>dom-broker</name>
+                     <data-store xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
+                        <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">prefix:dom-data-store</type>
+                        <name>ref_hash-map-data-store</name>
+                     </data-store>
+                  </module>
+               </modules>
+               <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+                  <service>
+                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">prefix:schema-service</type>
+                     <instance>
+                        <name>ref_yang-schema-service</name>
+                        <provider>/modules/module[type='schema-service-singleton'][name='yang-schema-service']</provider>
+                     </instance>
+                  </service>
+                  <service>
+                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">prefix:dom-data-store</type>
+                     <instance>
+                        <name>ref_hash-map-data-store</name>
+                        <provider>/modules/module[type='hash-map-data-store'][name='hash-map-data-store']</provider>
+                     </instance>
+                  </service>
+                  <service>
+                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">prefix:dom-broker-osgi-registry</type>
+                     <instance>
+                        <name>ref_dom-broker</name>
+                        <provider>/modules/module[type='dom-broker-impl'][name='dom-broker']</provider>
+                     </instance>
+                  </service>
+                  <service>
+                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:test">prefix:testing</type>
+                     <instance>
+                        <name>ref_id-test</name>
+                        <provider>/modules/module[type='impl-identity-test'][name='id-test']</provider>
+                     </instance>
+                  </service>
+                  <service>
+                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-dom-mapping-service</type>
+                     <instance>
+                        <name>ref_runtime-mapping-singleton</name>
+                        <provider>/modules/module[type='runtime-generated-mapping'][name='runtime-mapping-singleton']</provider>
+                     </instance>
+                  </service>
+                  <service>
+                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-data-consumer-broker</type>
+                     <instance>
+                        <name>ref_binding-data-broker</name>
+                        <provider>/modules/module[type='binding-data-broker'][name='binding-data-broker']</provider>
+                     </instance>
+                  </service>
+                  <service>
+                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-rpc-registry</type>
+                     <instance>
+                        <name>ref_binding-broker-impl</name>
+                        <provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
+                     </instance>
+                  </service>
+                  <service>
+                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-notification-service</type>
+                     <instance>
+                        <name>ref_binding-notification-broker</name>
+                        <provider>/modules/module[type='binding-notification-broker'][name='binding-notification-broker']</provider>
+                     </instance>
+                  </service>
+                  <service>
+                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-broker-osgi-registry</type>
+                     <instance>
+                        <name>ref_binding-broker-impl</name>
+                        <provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
+                     </instance>
+                  </service>
+                  <service>
+                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-notification-subscription-service</type>
+                     <instance>
+                        <name>ref_binding-notification-broker</name>
+                        <provider>/modules/module[type='binding-notification-broker'][name='binding-notification-broker']</provider>
+                     </instance>
+                  </service>
+                  <service>
+                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">prefix:binding-data-broker</type>
+                     <instance>
+                        <name>ref_binding-data-broker</name>
+                        <provider>/modules/module[type='binding-data-broker'][name='binding-data-broker']</provider>
+                     </instance>
+                  </service>
+               </services>
+            </data>
+         </configuration>
+      </snapshot>
+   </snapshots>
+</persisted-snapshots>
diff --git a/opendaylight/netconf/netconf-it/src/test/resources/netconfMessages/commit.xml b/opendaylight/netconf/netconf-it/src/test/resources/netconfMessages/commit.xml
new file mode 100644 (file)
index 0000000..ffdf132
--- /dev/null
@@ -0,0 +1,3 @@
+<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="101">
+    <commit></commit>
+</rpc>
diff --git a/opendaylight/netconf/netconf-it/src/test/resources/netconfMessages/editConfig_identities.xml b/opendaylight/netconf/netconf-it/src/test/resources/netconfMessages/editConfig_identities.xml
new file mode 100644 (file)
index 0000000..cf9f3e5
--- /dev/null
@@ -0,0 +1,37 @@
+<rpc message-id="a" a="64" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+<edit-config>
+    <target>
+        <candidate/>
+    </target>
+    <test-option>
+        set
+    </test-option>
+    <default-operation>merge</default-operation>
+    <config>
+        <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+            <module>
+                <type xmlns:test-impl="urn:opendaylight:params:xml:ns:yang:controller:test:impl">
+                    test-impl:impl-identity-test
+                </type>
+                <name>id-test</name>
+                <identities>
+                    <afi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:test:types">prefix:test-identity1</afi>
+                    <safi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:test:types">prefix:test-identity2</safi>
+                </identities>
+                <identities>
+                    <afi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:test:types">prefix:test-identity2</afi>
+                    <safi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:test:types">prefix:test-identity1</safi>
+                </identities>
+                <identities-container>
+                    <afi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:test:types">prefix:test-identity2</afi>
+                </identities-container>
+                <afi xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:test:types">prefix:test-identity1</afi>
+            </module>
+        </modules>
+
+        <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+
+        </services>
+    </config>
+</edit-config>
+</rpc>
diff --git a/opendaylight/netconf/netconf-it/src/test/resources/netconfMessages/getConfig.xml b/opendaylight/netconf/netconf-it/src/test/resources/netconfMessages/getConfig.xml
new file mode 100644 (file)
index 0000000..39efb49
--- /dev/null
@@ -0,0 +1,7 @@
+<rpc id="a" a="64" xmlnx="a:b:c:d" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="101">
+    <get-config>
+        <source>
+            <running/>
+        </source>
+    </get-config>
+</rpc>
index d9aa0ab64d55dfd27740bf4dd50dc8b7b322f4f8..18c27238e9017d44cfe26ffb997c597807af81ff 100644 (file)
@@ -4,7 +4,7 @@
     <parent>
         <artifactId>netconf-subsystem</artifactId>
         <groupId>org.opendaylight.controller</groupId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>netconf-mapping-api</artifactId>
index d1fb6aabeb750eac9517e5af012ae90446611c57..568aca9063c64a4e3af26fc20e199957be576780 100644 (file)
@@ -3,7 +3,7 @@
     <parent>
         <artifactId>netconf-subsystem</artifactId>
         <groupId>org.opendaylight.controller</groupId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>netconf-monitoring</artifactId>
index efad2148e979ae697e0255833ec442928e73494e..73e0a467c040cc3cc8e7f3518e2a209ebdddb453 100644 (file)
@@ -2,7 +2,7 @@
     <parent>
         <artifactId>netconf-subsystem</artifactId>
         <groupId>org.opendaylight.controller</groupId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
         <relativePath>../</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
index e5bab5633ba023f1b5d78522007b4d7e937c06de..5df329def023f2c5216b08a3f9a7bbef29bccc23 100644 (file)
@@ -4,7 +4,7 @@
     <parent>
         <artifactId>netconf-subsystem</artifactId>
         <groupId>org.opendaylight.controller</groupId>
-        <version>0.2.4-SNAPSHOT</version>
+        <version>0.2.5-SNAPSHOT</version>
     </parent>
     <artifactId>netconf-util</artifactId>
     <name>${project.artifactId}</name>
index 28cb4d8194b6c6b67d8afe17790974a5584de4f2..457dda3080fa48adb18e170ba1e36d01d10513f6 100644 (file)
@@ -45,7 +45,7 @@ public class XmlFileLoader {
     public static Document xmlFileToDocument(final String fileName) throws IOException, SAXException,
             ParserConfigurationException {
         try (InputStream resourceAsStream = XmlFileLoader.class.getClassLoader().getResourceAsStream(fileName)) {
-            Preconditions.checkNotNull(resourceAsStream);
+            Preconditions.checkNotNull(resourceAsStream, fileName);
             final Document doc = XmlUtil.readXmlToDocument(resourceAsStream);
             return doc;
         }
index 2c2ef3b5076155d2f34303e56f32eef4ff411b94..ae75657e5a71876b00146b313ed75f6585928bd0 100644 (file)
@@ -8,7 +8,7 @@
         <relativePath>../commons/opendaylight</relativePath>
     </parent>
 
-    <version>0.2.4-SNAPSHOT</version>
+    <version>0.2.5-SNAPSHOT</version>
     <artifactId>netconf-subsystem</artifactId>
     <packaging>pom</packaging>
     <name>${project.artifactId}</name>
@@ -48,8 +48,6 @@
         <maven.bundle.version>2.4.0</maven.bundle.version>
         <slf4j.version>1.7.2</slf4j.version>
         <netconf.netty.version>4.0.10.Final</netconf.netty.version>
-        <netconf.version>0.2.4-SNAPSHOT</netconf.version>
-        <config.version>0.2.4-SNAPSHOT</config.version>
         <salGeneratorPath>${project.build.directory}/generated-sources/sal</salGeneratorPath>
     </properties>
 
index 680b028f9adf6f4de276188745cbeb6ceb4092b9..f93191220b407b43080595edfff2f771d7160aa4 100644 (file)
@@ -37,12 +37,15 @@ import org.opendaylight.controller.networkconfig.neutron.NeutronPort;
 import org.opendaylight.controller.networkconfig.neutron.NeutronSubnet;
 import org.opendaylight.controller.networkconfig.neutron.Neutron_IPs;
 import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
 import org.opendaylight.controller.sal.utils.ServiceHelper;
 
 /**
- * Open DOVE Northbound REST APIs.<br>
- * This class provides REST APIs for managing the open DOVE
+ * Neutron Northbound REST APIs.<br>
+ * This class provides REST APIs for managing Neutron Floating IPs
  *
  * <br>
  * <br>
@@ -139,7 +142,7 @@ public class NeutronFloatingIPsNorthbound {
                     + RestMessages.SERVICEUNAVAILABLE.toString());
         }
         if (!floatingIPInterface.floatingIPExists(floatingipUUID))
-            return Response.status(404).build();
+            throw new ResourceNotFoundException("Floating IP UUID doesn't exist.");
         if (fields.size() > 0) {
             NeutronFloatingIP ans = floatingIPInterface.getFloatingIP(floatingipUUID);
             return Response.status(200).entity(
@@ -187,42 +190,42 @@ public class NeutronFloatingIPsNorthbound {
             NeutronFloatingIP singleton = input.getSingleton();
             // check existence of id in cache and return badrequest if exists
             if (floatingIPInterface.floatingIPExists(singleton.getID()))
-                return Response.status(400).build();
+                throw new BadRequestException("Floating IP UUID already exists.");
             // check if the external network is specified, exists, and is an external network
             String externalNetworkUUID = singleton.getFloatingNetworkUUID();
             if (externalNetworkUUID == null)
-                return Response.status(400).build();
+                throw new BadRequestException("external network UUID doesn't exist.");
             if (!networkInterface.networkExists(externalNetworkUUID))
-                return Response.status(400).build();
+                throw new BadRequestException("external network UUID doesn't exist.");
             NeutronNetwork externNetwork = networkInterface.getNetwork(externalNetworkUUID);
             if (!externNetwork.isRouterExternal())
-                return Response.status(400).build();
+                throw new BadRequestException("external network isn't marked router:external");
             // if floating IP is specified, make sure it can come from the network
             String floatingIP = singleton.getFloatingIPAddress();
             if (floatingIP != null) {
                 if (externNetwork.getSubnets().size() > 1)
-                    return Response.status(400).build();
+                    throw new BadRequestException("external network doesn't have a subnet");
                 NeutronSubnet externSubnet = subnetInterface.getSubnet(externNetwork.getSubnets().get(0));
                 if (!externSubnet.isValidIP(floatingIP))
-                    return Response.status(400).build();
+                    throw new BadRequestException("external IP isn't valid for the specified subnet.");
                 if (externSubnet.isIPInUse(floatingIP))
-                    return Response.status(409).build();
+                    throw new ResourceConflictException("floating IP is in use.");
             }
             // if port_id is specified, then check that the port exists and has at least one IP
             String port_id = singleton.getPortUUID();
             if (port_id != null) {
                 String fixedIP = null;        // used for the fixedIP calculation
                 if (!portInterface.portExists(port_id))
-                    return Response.status(404).build();
+                    throw new ResourceNotFoundException("Port UUID doesn't exist.");
                 NeutronPort port = portInterface.getPort(port_id);
                 if (port.getFixedIPs().size() < 1)
-                    return Response.status(400).build();
+                    throw new BadRequestException("port UUID doesn't have an IP address.");
                 // if there is more than one fixed IP then check for fixed_ip_address
                 // and that it is in the list of port addresses
                 if (port.getFixedIPs().size() > 1) {
                     fixedIP = singleton.getFixedIPAddress();
                     if (fixedIP == null)
-                        return Response.status(400).build();
+                        throw new BadRequestException("fixed IP address doesn't exist.");
                     Iterator<Neutron_IPs> i = port.getFixedIPs().iterator();
                     boolean validFixedIP = false;
                     while (i.hasNext() && !validFixedIP) {
@@ -231,15 +234,15 @@ public class NeutronFloatingIPsNorthbound {
                             validFixedIP = true;
                     }
                     if (!validFixedIP)
-                        return Response.status(400).build();
+                        throw new BadRequestException("can't find a valid fixed IP address");
                 } else {
                     fixedIP = port.getFixedIPs().get(0).getIpAddress();
                     if (singleton.getFixedIPAddress() != null && !fixedIP.equalsIgnoreCase(singleton.getFixedIPAddress()))
-                        return Response.status(400).build();
+                        throw new BadRequestException("mismatched fixed IP address in request");
                 }
                 //lastly check that this fixed IP address isn't already used
                 if (port.isBoundToFloatingIP(fixedIP))
-                    return Response.status(409).build();
+                    throw new ResourceConflictException("fixed IP is in use.");
                 singleton.setFixedIPAddress(fixedIP);
             }
             Object[] instances = ServiceHelper.getGlobalInstances(INeutronFloatingIPAware.class, this, null);
@@ -259,7 +262,7 @@ public class NeutronFloatingIPsNorthbound {
                 }
             }
         } else {
-            return Response.status(400).build();
+            throw new BadRequestException("only singleton requests allowed.");
         }
         return Response.status(201).entity(input).build();
     }
@@ -303,14 +306,14 @@ public class NeutronFloatingIPsNorthbound {
                     + RestMessages.SERVICEUNAVAILABLE.toString());
         }
         if (!floatingIPInterface.floatingIPExists(floatingipUUID))
-            return Response.status(404).build();
+            throw new ResourceNotFoundException("Floating IP UUID doesn't exist.");
 
         NeutronFloatingIP sourceFloatingIP = floatingIPInterface.getFloatingIP(floatingipUUID);
         if (!input.isSingleton())
-            return Response.status(400).build();
+            throw new BadRequestException("only singleton requests allowed.");
         NeutronFloatingIP singleton = input.getSingleton();
         if (singleton.getID() != null)
-            return Response.status(400).build();
+            throw new BadRequestException("singleton UUID doesn't exist.");
 
         NeutronNetwork externNetwork = networkInterface.getNetwork(
                 sourceFloatingIP.getFloatingNetworkUUID());
@@ -319,12 +322,12 @@ public class NeutronFloatingIPsNorthbound {
         String floatingIP = singleton.getFloatingIPAddress();
         if (floatingIP != null) {
             if (externNetwork.getSubnets().size() > 1)
-                return Response.status(400).build();
+                throw new BadRequestException("external network doesn't have a subnet.");
             NeutronSubnet externSubnet = subnetInterface.getSubnet(externNetwork.getSubnets().get(0));
             if (!externSubnet.isValidIP(floatingIP))
-                return Response.status(400).build();
+                throw new BadRequestException("floating IP not valid for external subnet");
             if (externSubnet.isIPInUse(floatingIP))
-                return Response.status(409).build();
+                throw new ResourceConflictException("floating IP is in use.");
         }
 
         // if port_id is specified, then check that the port exists and has at least one IP
@@ -332,16 +335,16 @@ public class NeutronFloatingIPsNorthbound {
         if (port_id != null) {
             String fixedIP = null;        // used for the fixedIP calculation
             if (!portInterface.portExists(port_id))
-                return Response.status(404).build();
+                throw new ResourceNotFoundException("Port UUID doesn't exist.");
             NeutronPort port = portInterface.getPort(port_id);
             if (port.getFixedIPs().size() < 1)
-                return Response.status(400).build();
+                throw new BadRequestException("port ID doesn't have a fixed IP address.");
             // if there is more than one fixed IP then check for fixed_ip_address
             // and that it is in the list of port addresses
             if (port.getFixedIPs().size() > 1) {
                 fixedIP = singleton.getFixedIPAddress();
                 if (fixedIP == null)
-                    return Response.status(400).build();
+                    throw new BadRequestException("request doesn't have a fixed IP address");
                 Iterator<Neutron_IPs> i = port.getFixedIPs().iterator();
                 boolean validFixedIP = false;
                 while (i.hasNext() && !validFixedIP) {
@@ -350,16 +353,16 @@ public class NeutronFloatingIPsNorthbound {
                         validFixedIP = true;
                 }
                 if (!validFixedIP)
-                    return Response.status(400).build();
+                    throw new BadRequestException("couldn't find a valid fixed IP address");
             } else {
                 fixedIP = port.getFixedIPs().get(0).getIpAddress();
                 if (singleton.getFixedIPAddress() != null &&
                         !fixedIP.equalsIgnoreCase(singleton.getFixedIPAddress()))
-                    return Response.status(400).build();
+                    throw new BadRequestException("mismatch in fixed IP addresses");
             }
             //lastly check that this fixed IP address isn't already used
             if (port.isBoundToFloatingIP(fixedIP))
-                return Response.status(409).build();
+                throw new ResourceConflictException("fixed IP is in use.");
             singleton.setFixedIPAddress(fixedIP);
         }
         NeutronFloatingIP target = floatingIPInterface.getFloatingIP(floatingipUUID);
@@ -403,7 +406,7 @@ public class NeutronFloatingIPsNorthbound {
                     + RestMessages.SERVICEUNAVAILABLE.toString());
         }
         if (!floatingIPInterface.floatingIPExists(floatingipUUID))
-            return Response.status(404).build();
+            throw new ResourceNotFoundException("Floating IP UUID doesn't exist.");
         // TODO: need to undo port association if it exists
         NeutronFloatingIP singleton = floatingIPInterface.getFloatingIP(floatingipUUID);
         Object[] instances = ServiceHelper.getGlobalInstances(INeutronFloatingIPAware.class, this, null);
index c08ee80e24c44f3551d949e0ff607c7264be9167..d7437c831d4eb38a248c72bbe4050114a358e32e 100644 (file)
@@ -33,12 +33,15 @@ import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkCRUD;
 import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
 import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
 import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
 import org.opendaylight.controller.sal.utils.ServiceHelper;
 
 /**
- * Open DOVE Northbound REST APIs for Network.<br>
- * This class provides REST APIs for managing open DOVE internals related to Networks
+ * Neutron Northbound REST APIs for Network.<br>
+ * This class provides REST APIs for managing neutron Networks
  *
  * <br>
  * <br>
@@ -154,7 +157,7 @@ public class NeutronNetworksNorthbound {
                     + RestMessages.SERVICEUNAVAILABLE.toString());
         }
         if (!networkInterface.networkExists(netUUID)) {
-            return Response.status(404).build();
+            throw new ResourceNotFoundException("network UUID does not exist.");
         }
         if (fields.size() > 0) {
             NeutronNetwork ans = networkInterface.getNetwork(netUUID);
@@ -189,7 +192,7 @@ public class NeutronNetworksNorthbound {
              * network ID can't already exist
              */
             if (networkInterface.networkExists(singleton.getID())) {
-                return Response.status(400).build();
+                throw new BadRequestException("network UUID already exists");
             }
 
             Object[] instances = ServiceHelper.getGlobalInstances(INeutronNetworkAware.class, this, null);
@@ -226,10 +229,10 @@ public class NeutronNetworksNorthbound {
                  * already in this bulk request
                  */
                 if (networkInterface.networkExists(test.getID())) {
-                    return Response.status(400).build();
+                    throw new BadRequestException("network UUID already exists");
                 }
                 if (testMap.containsKey(test.getID())) {
-                    return Response.status(400).build();
+                    throw new BadRequestException("network UUID already exists");
                 }
                 if (instances != null) {
                     for (Object instance: instances) {
@@ -285,10 +288,10 @@ public class NeutronNetworksNorthbound {
          * network has to exist and only a single delta is supported
          */
         if (!networkInterface.networkExists(netUUID)) {
-            return Response.status(404).build();
+            throw new ResourceNotFoundException("network UUID does not exist.");
         }
         if (!input.isSingleton()) {
-            return Response.status(400).build();
+            throw new BadRequestException("only singleton edits supported");
         }
         NeutronNetwork delta = input.getSingleton();
 
@@ -297,7 +300,7 @@ public class NeutronNetworksNorthbound {
          */
         if (delta.getID() != null || delta.getTenantID() != null ||
                 delta.getStatus() != null) {
-            return Response.status(400).build();
+            throw new BadRequestException("attribute edit blocked by Neutron");
         }
 
         Object[] instances = ServiceHelper.getGlobalInstances(INeutronNetworkAware.class, this, null);
@@ -347,10 +350,10 @@ public class NeutronNetworksNorthbound {
          * network has to exist and not be in use before it can be removed
          */
         if (!networkInterface.networkExists(netUUID)) {
-            return Response.status(404).build();
+            throw new ResourceNotFoundException("network UUID does not exist.");
         }
         if (networkInterface.networkInUse(netUUID)) {
-            return Response.status(409).build();
+            throw new ResourceConflictException("Network ID in use");
         }
 
         NeutronNetwork singleton = networkInterface.getNetwork(netUUID);
index c26e0229d0271ed6a6a0a10f0e17755176f69595..9f24e79ea02ab3fd6fbbd722fe8c86054a3b4470 100644 (file)
@@ -36,12 +36,15 @@ import org.opendaylight.controller.networkconfig.neutron.NeutronPort;
 import org.opendaylight.controller.networkconfig.neutron.NeutronSubnet;
 import org.opendaylight.controller.networkconfig.neutron.Neutron_IPs;
 import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
 import org.opendaylight.controller.sal.utils.ServiceHelper;
 
 /**
- * Open DOVE Northbound REST APIs.<br>
- * This class provides REST APIs for managing the open DOVE
+ * Neutron Northbound REST APIs.<br>
+ * This class provides REST APIs for managing neutron port objects
  *
  * <br>
  * <br>
@@ -148,7 +151,7 @@ public class NeutronPortsNorthbound {
                     + RestMessages.SERVICEUNAVAILABLE.toString());
         }
         if (!portInterface.portExists(portUUID)) {
-            return Response.status(404).build();
+            throw new ResourceNotFoundException("port UUID does not exist.");
         }
         if (fields.size() > 0) {
             NeutronPort ans = portInterface.getPort(portUUID);
@@ -200,20 +203,20 @@ public class NeutronPortsNorthbound {
              * have a valid MAC and the MAC not be in use
              */
             if (singleton.getNetworkUUID() == null) {
-                return Response.status(400).build();
+                throw new BadRequestException("network UUID musy be specified");
             }
             if (portInterface.portExists(singleton.getID())) {
-                return Response.status(400).build();
+                throw new BadRequestException("port UUID already exists");
             }
             if (!networkInterface.networkExists(singleton.getNetworkUUID())) {
-                return Response.status(404).build();
+                throw new ResourceNotFoundException("network UUID does not exist.");
             }
             if (singleton.getMacAddress() == null ||
                     !singleton.getMacAddress().matches(mac_regex)) {
-                return Response.status(400).build();
+                throw new BadRequestException("MAC address not properly formatted");
             }
             if (portInterface.macInUse(singleton.getMacAddress())) {
-                return Response.status(409).build();
+                throw new ResourceConflictException("MAC Address is in use.");
             }
             Object[] instances = ServiceHelper.getGlobalInstances(INeutronPortAware.class, this, null);
             if (instances != null) {
@@ -237,21 +240,21 @@ public class NeutronPortsNorthbound {
                 while (fixedIPIterator.hasNext()) {
                     Neutron_IPs ip = fixedIPIterator.next();
                     if (ip.getSubnetUUID() == null) {
-                        return Response.status(400).build();
+                        throw new BadRequestException("subnet UUID not specified");
                     }
                     if (!subnetInterface.subnetExists(ip.getSubnetUUID())) {
-                        return Response.status(400).build();
+                        throw new BadRequestException("subnet UUID must exists");
                     }
                     NeutronSubnet subnet = subnetInterface.getSubnet(ip.getSubnetUUID());
                     if (!singleton.getNetworkUUID().equalsIgnoreCase(subnet.getNetworkUUID())) {
-                        return Response.status(400).build();
+                        throw new BadRequestException("network UUID must match that of subnet");
                     }
                     if (ip.getIpAddress() != null) {
                         if (!subnet.isValidIP(ip.getIpAddress())) {
-                            return Response.status(400).build();
+                            throw new BadRequestException("IP address is not valid");
                         }
                         if (subnet.isIPInUse(ip.getIpAddress())) {
-                            return Response.status(409).build();
+                            throw new ResourceConflictException("IP address is in use.");
                         }
                     }
                 }
@@ -279,32 +282,32 @@ public class NeutronPortsNorthbound {
                  * can't already contain a new port with the same UUID
                  */
                 if (portInterface.portExists(test.getID())) {
-                    return Response.status(400).build();
+                    throw new BadRequestException("port UUID already exists");
                 }
                 if (testMap.containsKey(test.getID())) {
-                    return Response.status(400).build();
+                    throw new BadRequestException("port UUID already exists");
                 }
                 for (NeutronPort check : testMap.values()) {
                     if (test.getMacAddress().equalsIgnoreCase(check.getMacAddress())) {
-                        return Response.status(409).build();
+                        throw new ResourceConflictException("MAC address already allocated");
                     }
                     for (Neutron_IPs test_fixedIP : test.getFixedIPs()) {
                         for (Neutron_IPs check_fixedIP : check.getFixedIPs()) {
                             if (test_fixedIP.getIpAddress().equals(check_fixedIP.getIpAddress())) {
-                                return Response.status(409).build();
+                                throw new ResourceConflictException("IP address already allocated");
                             }
                         }
                     }
                 }
                 testMap.put(test.getID(), test);
                 if (!networkInterface.networkExists(test.getNetworkUUID())) {
-                    return Response.status(404).build();
+                    throw new ResourceNotFoundException("network UUID does not exist.");
                 }
                 if (!test.getMacAddress().matches(mac_regex)) {
-                    return Response.status(400).build();
+                    throw new BadRequestException("MAC address not properly formatted");
                 }
                 if (portInterface.macInUse(test.getMacAddress())) {
-                    return Response.status(409).build();
+                    throw new ResourceConflictException("MAC address in use");
                 }
                 if (instances != null) {
                     for (Object instance : instances) {
@@ -327,23 +330,23 @@ public class NeutronPortsNorthbound {
                     while (fixedIPIterator.hasNext()) {
                         Neutron_IPs ip = fixedIPIterator.next();
                         if (ip.getSubnetUUID() == null) {
-                            return Response.status(400).build();
+                            throw new BadRequestException("subnet UUID must be specified");
                         }
                         if (!subnetInterface.subnetExists(ip.getSubnetUUID())) {
-                            return Response.status(400).build();
+                            throw new BadRequestException("subnet UUID doesn't exists");
                         }
                         NeutronSubnet subnet = subnetInterface.getSubnet(ip.getSubnetUUID());
                         if (!test.getNetworkUUID().equalsIgnoreCase(subnet.getNetworkUUID())) {
-                            return Response.status(400).build();
+                            throw new BadRequestException("network UUID must match that of subnet");
                         }
                         if (ip.getIpAddress() != null) {
                             if (!subnet.isValidIP(ip.getIpAddress())) {
-                                return Response.status(400).build();
+                                throw new BadRequestException("ip address not valid");
                             }
                             //TODO: need to add consideration for a fixed IP being assigned the same address as a allocated IP in the
                             //same bulk create
                             if (subnet.isIPInUse(ip.getIpAddress())) {
-                                return Response.status(409).build();
+                                throw new ResourceConflictException("IP address in use");
                             }
                         }
                     }
@@ -399,11 +402,11 @@ public class NeutronPortsNorthbound {
 
         // port has to exist and only a single delta is supported
         if (!portInterface.portExists(portUUID)) {
-            return Response.status(404).build();
+            throw new ResourceNotFoundException("port UUID does not exist.");
         }
         NeutronPort target = portInterface.getPort(portUUID);
         if (!input.isSingleton()) {
-            return Response.status(400).build();
+            throw new BadRequestException("only singleton edit suported");
         }
         NeutronPort singleton = input.getSingleton();
         NeutronPort original = portInterface.getPort(portUUID);
@@ -411,7 +414,7 @@ public class NeutronPortsNorthbound {
         // deltas restricted by Neutron
         if (singleton.getID() != null || singleton.getTenantID() != null ||
                 singleton.getStatus() != null) {
-            return Response.status(400).build();
+            throw new BadRequestException("attribute change blocked by Neutron");
         }
 
         Object[] instances = ServiceHelper.getGlobalInstances(INeutronPortAware.class, this, null);
@@ -432,21 +435,21 @@ public class NeutronPortsNorthbound {
             while (fixedIPIterator.hasNext()) {
                 Neutron_IPs ip = fixedIPIterator.next();
                 if (ip.getSubnetUUID() == null) {
-                    return Response.status(400).build();
+                    throw new BadRequestException("subnet UUID must be specified");
                 }
                 if (!subnetInterface.subnetExists(ip.getSubnetUUID())) {
-                    return Response.status(400).build();
+                    throw new BadRequestException("subnet UUID doesn't exist.");
                 }
                 NeutronSubnet subnet = subnetInterface.getSubnet(ip.getSubnetUUID());
                 if (!target.getNetworkUUID().equalsIgnoreCase(subnet.getNetworkUUID())) {
-                    return Response.status(400).build();
+                    throw new BadRequestException("network UUID must match that of subnet");
                 }
                 if (ip.getIpAddress() != null) {
                     if (!subnet.isValidIP(ip.getIpAddress())) {
-                        return Response.status(400).build();
+                        throw new BadRequestException("invalid IP address");
                     }
                     if (subnet.isIPInUse(ip.getIpAddress())) {
-                        return Response.status(409).build();
+                        throw new ResourceConflictException("IP address in use");
                     }
                 }
             }
@@ -454,7 +457,7 @@ public class NeutronPortsNorthbound {
 
         //        TODO: Support change of security groups
         // update the port and return the modified object
-                portInterface.updatePort(portUUID, singleton);
+        portInterface.updatePort(portUUID, singleton);
         NeutronPort updatedPort = portInterface.getPort(portUUID);
         if (instances != null) {
             for (Object instance : instances) {
@@ -488,7 +491,7 @@ public class NeutronPortsNorthbound {
 
         // port has to exist and not be owned by anyone.  then it can be removed from the cache
         if (!portInterface.portExists(portUUID)) {
-            return Response.status(404).build();
+            throw new ResourceNotFoundException("port UUID does not exist.");
         }
         NeutronPort port = portInterface.getPort(portUUID);
         if (port.getDeviceID() != null ||
index fc7e0f7efbf429014859c760caf86add6f326518..17b2fcfcf9ef43437903f499dc4da2aceb61983b 100644 (file)
@@ -37,13 +37,16 @@ import org.opendaylight.controller.networkconfig.neutron.NeutronRouter;
 import org.opendaylight.controller.networkconfig.neutron.NeutronRouter_Interface;
 import org.opendaylight.controller.networkconfig.neutron.NeutronSubnet;
 import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
 import org.opendaylight.controller.sal.utils.ServiceHelper;
 
 
 /**
- * Open DOVE Northbound REST APIs.<br>
- * This class provides REST APIs for managing the open DOVE
+ * Neutron Northbound REST APIs.<br>
+ * This class provides REST APIs for managing neutron routers
  *
  * <br>
  * <br>
@@ -141,8 +144,9 @@ public class NeutronRoutersNorthbound {
             throw new ServiceUnavailableException("Router CRUD Interface "
                     + RestMessages.SERVICEUNAVAILABLE.toString());
         }
-        if (!routerInterface.routerExists(routerUUID))
-            return Response.status(404).build();
+        if (!routerInterface.routerExists(routerUUID)) {
+            throw new ResourceNotFoundException("Router UUID not found");
+        }
         if (fields.size() > 0) {
             NeutronRouter ans = routerInterface.getRouter(routerUUID);
             return Response.status(200).entity(
@@ -184,14 +188,14 @@ public class NeutronRoutersNorthbound {
              * exists and has been designated as "router:external"
              */
             if (routerInterface.routerExists(singleton.getID()))
-                return Response.status(400).build();
+                throw new BadRequestException("router UUID already exists");
             if (singleton.getExternalGatewayInfo() != null) {
                 String externNetworkPtr = singleton.getExternalGatewayInfo().getNetworkID();
                 if (!networkInterface.networkExists(externNetworkPtr))
-                    return Response.status(400).build();
+                    throw new BadRequestException("External Network Pointer doesn't exist");
                 NeutronNetwork externNetwork = networkInterface.getNetwork(externNetworkPtr);
                 if (!externNetwork.isRouterExternal())
-                    return Response.status(400).build();
+                    throw new BadRequestException("External Network Pointer isn't marked as router:external");
             }
             Object[] instances = ServiceHelper.getGlobalInstances(INeutronRouterAware.class, this, null);
             if (instances != null) {
@@ -218,7 +222,7 @@ public class NeutronRoutersNorthbound {
             /*
              * only singleton router creates supported
              */
-            return Response.status(400).build();
+            throw new BadRequestException("Only singleton router creates supported");
         }
         return Response.status(201).entity(input).build();
     }
@@ -256,9 +260,9 @@ public class NeutronRoutersNorthbound {
          * router has to exist and only a single delta can be supplied
          */
         if (!routerInterface.routerExists(routerUUID))
-            return Response.status(404).build();
+            throw new ResourceNotFoundException("Router UUID not found");
         if (!input.isSingleton())
-            return Response.status(400).build();
+            throw new BadRequestException("Only single router deltas supported");
         NeutronRouter singleton = input.getSingleton();
         NeutronRouter original = routerInterface.getRouter(routerUUID);
 
@@ -267,7 +271,7 @@ public class NeutronRoutersNorthbound {
          */
         if (singleton.getID() != null || singleton.getTenantID() != null ||
                 singleton.getStatus() != null)
-            return Response.status(400).build();
+            throw new BadRequestException("Request attribute change not allowed");
 
         Object[] instances = ServiceHelper.getGlobalInstances(INeutronRouterAware.class, this, null);
         if (instances != null) {
@@ -285,10 +289,10 @@ public class NeutronRoutersNorthbound {
         if (singleton.getExternalGatewayInfo() != null) {
             String externNetworkPtr = singleton.getExternalGatewayInfo().getNetworkID();
             if (!networkInterface.networkExists(externNetworkPtr))
-                return Response.status(400).build();
+                throw new BadRequestException("External Network Pointer does not exist");
             NeutronNetwork externNetwork = networkInterface.getNetwork(externNetworkPtr);
             if (!externNetwork.isRouterExternal())
-                return Response.status(400).build();
+                throw new BadRequestException("External Network Pointer isn't marked as router:external");
         }
 
         /*
@@ -330,9 +334,9 @@ public class NeutronRoutersNorthbound {
          * verify that the router exists and is not in use before removing it
          */
         if (!routerInterface.routerExists(routerUUID))
-            return Response.status(404).build();
+            throw new ResourceNotFoundException("Router UUID not found");
         if (routerInterface.routerInUse(routerUUID))
-            return Response.status(409).build();
+            throw new ResourceConflictException("Router UUID in Use");
         NeutronRouter singleton = routerInterface.getRouter(routerUUID);
         Object[] instances = ServiceHelper.getGlobalInstances(INeutronRouterAware.class, this, null);
         if (instances != null) {
@@ -393,28 +397,27 @@ public class NeutronRoutersNorthbound {
          *  or a port id, but not both, this code assumes that the plugin has filled everything in for us and so both must be present
          */
         if (!routerInterface.routerExists(routerUUID))
-            return Response.status(400).build();
+            throw new BadRequestException("Router UUID doesn't exist");
         NeutronRouter target = routerInterface.getRouter(routerUUID);
         if (input.getSubnetUUID() == null ||
                     input.getPortUUID() == null)
-                return Response.status(400).build();
+            throw new BadRequestException("Must specify at subnet id, port id or both");
 
         // check that the port is part of the subnet
         NeutronSubnet targetSubnet = subnetInterface.getSubnet(input.getSubnetUUID());
         if (targetSubnet == null)
-            return Response.status(400).build();
+            throw new BadRequestException("Subnet id doesn't exist");
         NeutronPort targetPort = portInterface.getPort(input.getPortUUID());
         if (targetPort == null)
-            return Response.status(400).build();
+            throw new BadRequestException("Port id doesn't exist");
         if (!targetSubnet.getPortsInSubnet().contains(targetPort))
-            return Response.status(400).build();
+            throw new BadRequestException("Port id not part of subnet id");
 
         if (targetPort.getFixedIPs().size() != 1)
-            return Response.status(400).build();
+            throw new BadRequestException("Port id must have a single fixedIP address");
         if (targetPort.getDeviceID() != null ||
                 targetPort.getDeviceOwner() != null)
-            return Response.status(409).build();
-
+            throw new ResourceConflictException("Target Port already allocated");
         Object[] instances = ServiceHelper.getGlobalInstances(INeutronRouterAware.class, this, null);
         if (instances != null) {
             for (Object instance : instances) {
@@ -475,7 +478,7 @@ public class NeutronRoutersNorthbound {
 
         // verify the router exists
         if (!routerInterface.routerExists(routerUUID))
-            return Response.status(400).build();
+            throw new BadRequestException("Router does not exist");
         NeutronRouter target = routerInterface.getRouter(routerUUID);
 
         /*
@@ -486,7 +489,7 @@ public class NeutronRoutersNorthbound {
                 input.getSubnetUUID() != null) {
             NeutronPort port = portInterface.getGatewayPort(input.getSubnetUUID());
             if (port == null)
-                return Response.status(404).build();
+                throw new ResourceNotFoundException("Port UUID not found");
             input.setPortUUID(port.getID());
             input.setID(target.getID());
             input.setTenantID(target.getTenantID());
@@ -543,9 +546,18 @@ public class NeutronRoutersNorthbound {
         if (input.getPortUUID() != null &&
                 input.getSubnetUUID() != null) {
             NeutronPort port = portInterface.getPort(input.getPortUUID());
+            if (port == null) {
+                throw new ResourceNotFoundException("Port UUID not found");
+            }
+            if (port.getFixedIPs() == null) {
+                throw new ResourceNotFoundException("Port UUID jas no fixed IPs");
+            }
             NeutronSubnet subnet = subnetInterface.getSubnet(input.getSubnetUUID());
+            if (subnet == null) {
+                throw new ResourceNotFoundException("Subnet UUID not found");
+            }
             if (!subnet.isValidIP(port.getFixedIPs().get(0).getIpAddress()))
-                return Response.status(409).build();
+                throw new ResourceConflictException("Target Port IP not in Target Subnet");
             input.setID(target.getID());
             input.setTenantID(target.getTenantID());
             Object[] instances = ServiceHelper.getGlobalInstances(INeutronRouterAware.class, this, null);
@@ -566,6 +578,6 @@ public class NeutronRoutersNorthbound {
         }
 
         // have to specify either a port ID or a subnet ID
-        return Response.status(400).build();
+        throw new BadRequestException("Must specify port id or subnet id or both");
     }
 }
index dffac55c5030ac96da1b52bde366f009cbb4a63d..224fcb5f01ceaaaa662d2c9bbe0655892da463a2 100644 (file)
@@ -33,13 +33,16 @@ import org.opendaylight.controller.networkconfig.neutron.INeutronSubnetCRUD;
 import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
 import org.opendaylight.controller.networkconfig.neutron.NeutronSubnet;
 import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
 import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
 import org.opendaylight.controller.sal.utils.ServiceHelper;
 
 /**
- * Open DOVE Northbound REST APIs.<br>
- * This class provides REST APIs for managing open DOVE internals related to Subnets
+ * Neutron Northbound REST APIs for Subnets.<br>
+ * This class provides REST APIs for managing neutron Subnets
  *
  * <br>
  * <br>
@@ -142,7 +145,7 @@ public class NeutronSubnetsNorthbound {
                     + RestMessages.SERVICEUNAVAILABLE.toString());
         }
         if (!subnetInterface.subnetExists(subnetUUID)) {
-            return Response.status(404).build();
+            throw new ResourceNotFoundException("subnet UUID does not exist.");
         }
         if (fields.size() > 0) {
             NeutronSubnet ans = subnetInterface.getSubnet(subnetUUID);
@@ -190,19 +193,19 @@ public class NeutronSubnetsNorthbound {
              *  *then* add the subnet to the cache
              */
             if (subnetInterface.subnetExists(singleton.getID())) {
-                return Response.status(400).build();
+                throw new BadRequestException("subnet UUID already exists");
             }
             if (!networkInterface.networkExists(singleton.getNetworkUUID())) {
-                return Response.status(404).build();
+                throw new ResourceNotFoundException("network UUID does not exist.");
             }
             if (!singleton.isValidCIDR()) {
-                return Response.status(400).build();
+                throw new BadRequestException("invaild CIDR");
             }
             if (!singleton.initDefaults()) {
                 throw new InternalServerErrorException("subnet object could not be initialized properly");
             }
             if (singleton.gatewayIP_Pool_overlap()) {
-                return Response.status(409).build();
+                throw new ResourceConflictException("IP pool overlaps with gateway");
             }
             Object[] instances = ServiceHelper.getGlobalInstances(INeutronSubnetAware.class, this, null);
             if (instances != null) {
@@ -240,20 +243,20 @@ public class NeutronSubnetsNorthbound {
                     throw new InternalServerErrorException("subnet object could not be initialized properly");
                 }
                 if (subnetInterface.subnetExists(test.getID())) {
-                    return Response.status(400).build();
+                    throw new BadRequestException("subnet UUID already exists");
                 }
                 if (testMap.containsKey(test.getID())) {
-                    return Response.status(400).build();
+                    throw new BadRequestException("subnet UUID already exists");
                 }
                 testMap.put(test.getID(), test);
                 if (!networkInterface.networkExists(test.getNetworkUUID())) {
-                    return Response.status(404).build();
+                    throw new ResourceNotFoundException("network UUID does not exist.");
                 }
                 if (!test.isValidCIDR()) {
-                    return Response.status(400).build();
+                    throw new BadRequestException("Invalid CIDR");
                 }
                 if (test.gatewayIP_Pool_overlap()) {
-                    return Response.status(409).build();
+                    throw new ResourceConflictException("IP pool overlaps with gateway");
                 }
                 if (instances != null) {
                     for (Object instance : instances) {
@@ -312,10 +315,10 @@ public class NeutronSubnetsNorthbound {
          * verify the subnet exists and there is only one delta provided
          */
         if (!subnetInterface.subnetExists(subnetUUID)) {
-            return Response.status(404).build();
+            throw new ResourceNotFoundException("subnet UUID does not exist.");
         }
         if (!input.isSingleton()) {
-            return Response.status(400).build();
+            throw new BadRequestException("Only singleton edit supported");
         }
         NeutronSubnet delta = input.getSingleton();
         NeutronSubnet original = subnetInterface.getSubnet(subnetUUID);
@@ -326,7 +329,7 @@ public class NeutronSubnetsNorthbound {
         if (delta.getID() != null || delta.getTenantID() != null ||
                 delta.getIpVersion() != null || delta.getCidr() != null ||
                 delta.getAllocationPools() != null) {
-            return Response.status(400).build();
+            throw new BadRequestException("Attribute edit blocked by Neutron");
         }
 
         Object[] instances = ServiceHelper.getGlobalInstances(INeutronSubnetAware.class, this, null);
@@ -378,7 +381,7 @@ public class NeutronSubnetsNorthbound {
          * verify the subnet exists and it isn't currently in use
          */
         if (!subnetInterface.subnetExists(subnetUUID)) {
-            return Response.status(404).build();
+            throw new ResourceNotFoundException("subnet UUID does not exist.");
         }
         if (subnetInterface.subnetInUse(subnetUUID)) {
             return Response.status(409).build();
index 16868f55170deab4120ac7064fa849cb6da87c9d..326755309d7f01a01749055753a302d1248acd47 100644 (file)
@@ -15,7 +15,7 @@
   </scm>
 
   <artifactId>sal</artifactId>
-  <version>0.7.1-SNAPSHOT</version>
+  <version>0.8.1-SNAPSHOT</version>
   <packaging>bundle</packaging>
 
   <build>
index 7f398db6f12e8def650afa50be7a0ee888460906..0dffee9c474de57797117a218f4aa019e6a33e85 100644 (file)
@@ -85,6 +85,19 @@ public class Edge implements Serializable {
         }
     }
 
+    /**
+     * Create the reversed edge
+     * @return The reversed edge.
+     */
+    public Edge reverse() {
+        Edge re;
+        try {
+            re = new Edge(this.headNodeConnector, this.tailNodeConnector);
+        } catch (ConstructionException e) {
+            re = null;
+        }
+        return re;
+    }
     /**
      * getter of edge
      *
index 31b3ec6a5a164c96cc1c8ea04aa06e35b8197eab..ba2394131d84cb962696d2e955d4bbeb0866f277 100644 (file)
@@ -17,6 +17,8 @@
 package org.opendaylight.controller.sal.core;
 
 import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.List;
 
@@ -81,6 +83,39 @@ public class Path implements Serializable {
         this.edges = edges;
     }
 
+    /**
+     * Create the reversed path
+     * @return The reversed path
+     */
+    public Path reverse() {
+        int j = edges.size(); // size always > 0
+        Edge[]  aEdges = new Edge[j];
+        for (Edge e : edges) {
+            j--;
+            aEdges[j] = e.reverse();
+        }
+        Path rp;
+        try {
+         rp = new Path(Arrays.asList(aEdges));
+        } catch (ConstructionException ce) {
+            rp = null;
+        }
+        return rp;
+    }
+
+    /**
+     * Return the list of nodes of this path, the first node is the start node
+     * @return the list of nodes
+     */
+    public List<Node> getNodes() {
+        List<Node> nl = new ArrayList<Node>();
+        nl.add(this.getStartNode());
+        for (Edge e : edges) {
+            nl.add(e.getHeadNodeConnector().getNode());
+        }
+        return nl;
+    }
+
     /**
      * Copy Construct for a path
      *