Merge "Add support for multiple choice case statements within one augument in config...
authorTony Tkacik <ttkacik@cisco.com>
Mon, 17 Feb 2014 16:28:11 +0000 (16:28 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Mon, 17 Feb 2014 16:28:11 +0000 (16:28 +0000)
294 files changed:
opendaylight/appauth/pom.xml
opendaylight/appauth/src/main/java/org/opendaylight/controller/appauth/authorization/Authorization.java
opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/ARPReply.java
opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/ARPRequest.java
opendaylight/commons/opendaylight/pom.xml
opendaylight/commons/protocol-framework/pom.xml
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/DeserializerException.java [deleted file]
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/DocumentedException.java [deleted file]
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ProtocolHandlerFactory.java [deleted file]
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ProtocolMessageDecoder.java [deleted file]
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ProtocolMessageEncoder.java [deleted file]
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ProtocolMessageFactory.java [deleted file]
opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/protocol/framework/ComplementaryTest.java [deleted file]
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/osgi/BindingIndependentMappingServiceTracker.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/AbstractConfigTest.java
opendaylight/config/config-module-archetype/pom.xml [new file with mode: 0644]
opendaylight/config/config-module-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml [new file with mode: 0644]
opendaylight/config/config-module-archetype/src/main/resources/archetype-resources/pom.xml [new file with mode: 0644]
opendaylight/config/config-module-archetype/src/main/resources/archetype-resources/src/main/yang/__module-name__-impl.yang [new file with mode: 0644]
opendaylight/config/config-module-archetype/src/main/resources/archetype-resources/src/main/yang/__module-name__.yang [new file with mode: 0644]
opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/PersistException.java
opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/ConfigRegistryClientsTest.java
opendaylight/config/pom.xml
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/util/NameConflictException.java
opendaylight/config/yang-jmx-generator/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/SchemaContextTest.java
opendaylight/config/yang-test/pom.xml
opendaylight/configuration/api/src/main/java/org/opendaylight/controller/configuration/ConfigurationObject.java
opendaylight/configuration/api/src/main/java/org/opendaylight/controller/configuration/IConfigurationContainerService.java
opendaylight/configuration/implementation/src/main/java/org/opendaylight/controller/configuration/internal/ConfigurationService.java
opendaylight/configuration/implementation/src/main/java/org/opendaylight/controller/configuration/internal/ContainerConfigurationService.java
opendaylight/containermanager/implementation/src/main/java/org/opendaylight/controller/containermanager/internal/ContainerManager.java
opendaylight/distribution/opendaylight/pom.xml
opendaylight/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManager.java
opendaylight/hosttracker/api/src/main/java/org/opendaylight/controller/hosttracker/IPHostId.java
opendaylight/hosttracker/api/src/main/java/org/opendaylight/controller/hosttracker/IPMacHostId.java
opendaylight/hosttracker/implementation/src/main/java/org/opendaylight/controller/hosttracker/internal/HostTracker.java
opendaylight/logging/bridge/pom.xml
opendaylight/logging/bridge/src/main/java/org/opendaylight/controller/logging/bridge/internal/LogListenerImpl.java
opendaylight/logging/bridge/src/test/java/org/opendaylight/controller/logging/bridge/internal/LogListenerImplTest.java [new file with mode: 0644]
opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ComponentActivator.xtend
opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/FlowProgrammerAdapter.xtend
opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.xtend
opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryNotificationProvider.java [new file with mode: 0644]
opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeConnectorDataChangeListener.java [new file with mode: 0644]
opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowServiceAdapter.java
opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/FlowCapableInventoryProvider.xtend
opendaylight/md-sal/model/model-flow-base/pom.xml
opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-match-types.yang
opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-table-types.yang
opendaylight/md-sal/model/model-flow-service/pom.xml
opendaylight/md-sal/model/model-flow-service/src/main/yang/sal-flow.yang
opendaylight/md-sal/pom.xml
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/AbstractBindingAwareConsumer.java
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/AbstractBindingAwareProvider.java
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/NotificationProviderService.java
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/NotificationService.java
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcConsumerRegistry.java
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcProviderRegistry.java
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataModificationTransaction.java
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataProviderService.java
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataRefresher.java
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/RuntimeDataProvider.java
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/mount/MountInstance.java
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/mount/MountProviderService.java
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/rpc/RpcRouter.java
opendaylight/md-sal/sal-binding-broker/pom.xml
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingBrokerImplModule.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/NotificationBrokerImplModule.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java
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/DataTransactionImpl.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RootBindingAwareBroker.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcProviderRegistryImpl.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/DataModificationTracker.java
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/RuntimeCodeGeneratorTest.java
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/mock/ReferencableObjectKey.java
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingBrokerTestFactory.java
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug01Test.java
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug02Test.java
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug03Test.java
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/PutAugmentationTest.java
opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/CrossBrokerMountPointTest.java
opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java
opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/AbstractTest.java
opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/AbstractTestProvider.java
opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/NoficationTest.java
opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/RoutedServiceTest.java
opendaylight/md-sal/sal-binding-util/src/main/java/org/opendaylight/controller/md/sal/binding/util/AbstractBindingSalConsumerInstance.java
opendaylight/md-sal/sal-binding-util/src/main/java/org/opendaylight/controller/md/sal/binding/util/AbstractBindingSalProviderInstance.java
opendaylight/md-sal/sal-binding-util/src/main/java/org/opendaylight/controller/md/sal/binding/util/BindingContextUtils.java
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/TransactionStatus.java
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChangePublisher.java
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataModification.java
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/ListenerRegistry.java
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/RoutingUtils.java
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend [deleted file]
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeListenerRegistration.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/ImmutableDataChangeEvent.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/ListenerStateCapture.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/RootedChangeSet.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/TwoPhaseCommit.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/AbstractLockableDelegator.java
opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/Rpcs.java
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/AbstractProvider.java
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcProvisionRegistry.java
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataModificationTransaction.java
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/mount/MountProvisionInstance.java
opendaylight/md-sal/sal-dom-broker/pom.xml
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/ConsumerContextImpl.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/NotificationModule.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/NotificationRouterImpl.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/osgi/MountProviderServiceProxy.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/RpcProvisionRegistryProxy.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/spi/RpcRouter.java
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModule.java
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDevice.xtend
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDeviceListener.java
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDeviceTwoPhaseCommitTransaction.java
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfMapping.xtend
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfRemoteSchemaSourceProvider.java
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/YangModelInputStreamAdapter.java
opendaylight/md-sal/sal-netconf-connector/src/main/yang/odl-sal-netconf-connector-cfg.yang
opendaylight/md-sal/sal-remote/pom.xml
opendaylight/md-sal/sal-remote/src/main/java/org/opendaylight/controller/sal/restconf/service/impl/SalRemoteServiceImpl.java [deleted file]
opendaylight/md-sal/sal-remote/src/main/yang/opendaylight-md-sal-remote.yang
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/ServerImpl.java
opendaylight/md-sal/sal-rest-connector/pom.xml
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfProvider.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/StructuredDataToJsonProvider.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/StructuredDataToXmlProvider.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.xtend
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/ListenerAdapter.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/Notificator.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServer.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServerHandler.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServerInitializer.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/iml/varioustests/VariousTest.java [deleted file]
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonNotExistingLeafTypeTest.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnToXmlNotExistingLeafTypeTest.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestOperationUtils.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/IClientMessageCallback.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/WebSocketClient.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/WebSocketClientHandler.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/test/RestStream.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/full-versions/yangs/sal-remote@2014-01-14.yang [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/iana-if-type.yang [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/ietf-inet-types.yang [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/ietf-interfaces@2013-07-04.yang [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/ietf-restconf@2013-10-19.yang [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/ietf-yang-types.yang [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/module1.yang [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/module2.yang [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/module3.yang [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/modules-behind-mount-point/module1-behind-mount-point.yang [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/modules-behind-mount-point/module2-behind-mount-point.yang [new file with mode: 0644]
opendaylight/md-sal/sal-restconf-broker/pom.xml
opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationServiceImpl.java [deleted file]
opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/binding/impl/DataBrokerServiceImpl.java [moved from opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerServiceImpl.java with 88% similarity]
opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/SalRemoteServiceBroker.java
opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/event/RemoteDataChangeEvent.java [new file with mode: 0644]
opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/DataBrokerServiceImpl.java [new file with mode: 0644]
opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/NotificationServiceImpl.java [new file with mode: 0644]
opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/RemoteServicesFactory.java [new file with mode: 0644]
opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/RpcConsumerRegistryImpl.java [moved from opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcConsumerRegistryImpl.java with 58% similarity]
opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/RemoteDataChangeNotificationListener.java [new file with mode: 0644]
opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/RemoteNotificationListener.java [new file with mode: 0644]
opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/SalNotificationListener.java [new file with mode: 0644]
opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/tools/RemoteStreamTools.java [new file with mode: 0644]
opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/transactions/RemoteDataModificationTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-restconf-broker/src/test/java/org/opendaylight/controller/sal/binding/impl/test/DataBrokerImplTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-restconf-broker/src/test/java/org/opendaylight/controller/sal/binding/impl/test/NotificationServiceImplTest.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-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/ToasterProvider.java
opendaylight/md-sal/statistics-manager/pom.xml
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractListeningStatsTracker.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractStatsTracker.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowCapableContext.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowCapableTracker.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowComparator.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsEntry.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowTableStatsTracker.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupDescStatsTracker.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupStatsTracker.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterConfigStatsTracker.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterStatsTracker.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MultipartMessageManager.java
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeConnectorStatsTracker.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsAger.java [deleted file]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsHandler.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsEntry.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsTracker.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/RPCFailedException.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsListener.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsManagerActivator.java
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiter.java [deleted file]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateHandler.java [deleted file]
opendaylight/md-sal/statistics-manager/src/test/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiterTest.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/test/resources/log4j-test.xml [new file with mode: 0644]
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributeIfcSwitchStatement.java
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java
opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/AbstractNetconfSession.java [new file with mode: 0644]
opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfDeserializerException.java
opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfDocumentedException.java
opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfMessage.java
opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfSession.java
opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfSessionListener.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/AbstractNetconfClientNotifySessionListener.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClient.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientDispatcher.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSession.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionListener.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiator.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiatorFactory.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfSshClientDispatcher.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/SimpleNetconfClientSessionListener.java [new file with mode: 0644]
opendaylight/netconf/netconf-client/src/test/java/org/opendaylight/controller/netconf/client/SSHNetconfClientLiveTest.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerDispatcher.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSession.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionListener.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiator.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiatorFactory.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultCloseSession.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultGetSchema.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationRouterImpl.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/util/AdditionalHeaderUtil.java [deleted file]
opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/AdditionalHeaderParserTest.java
opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/ConcurrentClientsTest.java
opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/MessageParserTest.java
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java
opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/MonitoringConstants.java
opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/MonitoringSession.java
opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/package-info.java
opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/xml/JaxBSerializerTest.java
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProvider.java
opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/StubUserManager.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractChannelInitializer.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractNetconfSessionNegotiator.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfHandlerFactory.java [deleted file]
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfHelloMessageToXMLEncoder.java [new file with mode: 0644]
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfMessageChunkDecoder.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfMessageToXMLEncoder.java [new file with mode: 0644]
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfXMLToHelloMessageDecoder.java [new file with mode: 0644]
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfXMLToMessageDecoder.java [new file with mode: 0644]
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/ssh/virtualsocket/VirtualSocketException.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/mapping/AbstractNetconfOperation.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessage.java [new file with mode: 0644]
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessageAdditionalHeader.java [new file with mode: 0644]
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageAdditionalHeader.java [deleted file]
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactory.java [deleted file]
opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactoryTest.java
opendaylight/networkconfiguration/neutron/implementation/pom.xml
opendaylight/networkconfiguration/neutron/pom.xml
opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronSubnet.java
opendaylight/northbound/containermanager/pom.xml
opendaylight/northbound/integrationtest/pom.xml
opendaylight/northbound/networkconfiguration/neutron/pom.xml
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronPortsNorthbound.java
opendaylight/northbound/switchmanager/src/main/java/org/opendaylight/controller/switchmanager/northbound/SwitchNorthbound.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/Controller.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SecureMessageReadWriteService.java
opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DiscoveryService.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/NetUtils.java
opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/utils/NetUtilsTest.java
opendaylight/samples/simpleforwarding/src/main/java/org/opendaylight/controller/samples/simpleforwarding/internal/SimpleBroadcastHandlerImpl.java
opendaylight/statisticsmanager/implementation/src/main/java/org/opendaylight/controller/statisticsmanager/internal/StatisticsManager.java
opendaylight/switchmanager/api/src/main/java/org/opendaylight/controller/switchmanager/SwitchConfig.java
opendaylight/switchmanager/implementation/src/main/java/org/opendaylight/controller/switchmanager/internal/SwitchManager.java
opendaylight/usermanager/api/src/main/java/org/opendaylight/controller/usermanager/AuthenticatedUser.java
opendaylight/usermanager/api/src/test/java/org/opendaylight/controller/usermanager/AuthenticatedUserTest.java
opendaylight/web/flows/src/main/resources/js/page.js
opendaylight/web/troubleshoot/src/main/java/org/opendaylight/controller/troubleshoot/web/Troubleshoot.java
opendaylight/web/troubleshoot/src/main/resources/js/page.js

index 934fdfae80f21343dab801b0c964aadc36b479e6..30879c6565c1d78a462e5735c8104ce89965e945 100644 (file)
@@ -27,6 +27,7 @@
                 <configuration>
                     <instructions>
                         <Import-Package>
+                            org.opendaylight.controller.configuration,
                             org.opendaylight.controller.containermanager,
                             org.opendaylight.controller.sal.authorization,
                             org.opendaylight.controller.sal.utils,
     </build>
 
     <dependencies>
+      <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>configuration</artifactId>
+      </dependency>
       <dependency>
         <groupId>org.opendaylight.controller</groupId>
         <artifactId>sal</artifactId>
index 1992f5971120e37a83d3b6698732fecee2a64ee0..b70a79b4ae0bf9628dfb66d263f0315b5b350614 100644 (file)
@@ -16,6 +16,7 @@ import java.util.Map.Entry;
 import java.util.Set;
 import java.util.concurrent.ConcurrentMap;
 
+import org.opendaylight.controller.configuration.ConfigurationObject;
 import org.opendaylight.controller.containermanager.IContainerAuthorization;
 import org.opendaylight.controller.sal.authorization.AppRoleLevel;
 import org.opendaylight.controller.sal.authorization.IResourceAuthorization;
@@ -36,7 +37,7 @@ import org.slf4j.LoggerFactory;
  */
 public abstract class Authorization<T> implements IResourceAuthorization {
 private static final Logger logger = LoggerFactory.getLogger(Authorization.class);
-    private static final String namesRegex = "^[a-zA-Z0-9]+[{\\.|\\_|\\-}[a-zA-Z0-9]]*$";
+    private static final String namesRegex = ConfigurationObject.getRegularExpression();
     /*
      * The configured resource groups
      */
index e4388c598fb0eec94a0bb6cdb8f070b4f328af2c..a6ee60f65d14b5f47b6f7a6cc2db9331f6847d51 100644 (file)
@@ -18,7 +18,7 @@ import org.opendaylight.controller.sal.utils.HexEncode;
  * ARP Reply event wrapper
  */
 public class ARPReply extends ARPEvent {
-
+    private static final long serialVersionUID = 1L;
     private final NodeConnector port;
     private final byte[] tMac;
     private final byte[] sMac;
index 1b125ddeb20a898e26344e3ee91065f339f6d661..051635ad53f85f5a2344b0f2b23905de958781c1 100644 (file)
@@ -19,6 +19,7 @@ import org.opendaylight.controller.switchmanager.Subnet;
  * specified host
  */
 public class ARPRequest extends ARPEvent {
+    private static final long serialVersionUID = 1L;
     private final Subnet subnet;
     private final HostNodeConnector host;
 
index 9d4f8389925551c4142c4555b33e296d4cc11ec9..93845a356d40c5be253b01c1a30e6c0fcd8080a8 100644 (file)
@@ -4,7 +4,6 @@
   <prerequisites>
     <maven>3.0</maven>
   </prerequisites>
-  <groupId>org.opendaylight.controller</groupId>
   <artifactId>commons.opendaylight</artifactId>
   <version>1.4.2-SNAPSHOT</version>
   <packaging>pom</packaging>
     <testvm.argLine>-Xmx1024m -XX:MaxPermSize=256m</testvm.argLine>
     <guava.version>14.0.1</guava.version>
     <osgi.core.version>5.0.0</osgi.core.version>
-    <ietf-inet-types.version>2010.09.24.3</ietf-inet-types.version>
-    <ietf-yang-types.version>2010.09.24.3</ietf-yang-types.version>
-    <ietf-topology.version>2013.10.21.1</ietf-topology.version>
-    <opendaylight-l2-types.version>2013.08.27.3</opendaylight-l2-types.version>
-    <yang-ext.version>2013.09.07.3</yang-ext.version>
+    <ietf-inet-types.version>2010.09.24.4-SNAPSHOT</ietf-inet-types.version>
+    <ietf-yang-types.version>2010.09.24.4-SNAPSHOT</ietf-yang-types.version>
+    <ietf-topology.version>2013.10.21.2-SNAPSHOT</ietf-topology.version>
+    <opendaylight-l2-types.version>2013.08.27.4-SNAPSHOT</opendaylight-l2-types.version>
+    <yang-ext.version>2013.09.07.4-SNAPSHOT</yang-ext.version>
     <javassist.version>3.17.1-GA</javassist.version>
     <releaseplugin.version>2.3.2</releaseplugin.version>
     <commons.lang.version>3.1</commons.lang.version>
@@ -91,7 +90,7 @@
     <networkconfig.bridgedomain.northbound.version>0.0.3-SNAPSHOT</networkconfig.bridgedomain.northbound.version>
     <commons.httpclient.version>0.1.2-SNAPSHOT</commons.httpclient.version>
     <concepts.version>0.5.2-SNAPSHOT</concepts.version>
-    <protocol-framework.version>0.4.1-SNAPSHOT</protocol-framework.version>
+    <protocol-framework.version>0.5.0-SNAPSHOT</protocol-framework.version>
     <netty.version>4.0.10.Final</netty.version>
     <commons.io.version>2.4</commons.io.version>
     <bundlescanner.version>0.4.2-SNAPSHOT</bundlescanner.version>
             <artifactId>netty-common</artifactId>
             <version>${netty.version}</version>
         </dependency>
+        <dependency>
+            <groupId>io.netty</groupId>
+            <artifactId>netty-codec-http</artifactId>
+            <version>${netty.version}</version>
+        </dependency>
 
       <!-- yangtools dependencies -->
       <dependency>
        <artifactId>yang-model-api</artifactId>
        <version>${yangtools.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.opendaylight.yangtools</groupId>
+        <artifactId>yang-model-util</artifactId>
+        <version>${yangtools.version}</version>
+      </dependency>
+
       <dependency>
         <groupId>org.opendaylight.controller</groupId>
         <artifactId>hosttracker</artifactId>
         <artifactId>clustering.stub</artifactId>
         <version>${clustering.stub.version}</version>
       </dependency>
-      <dependency>
-        <groupId>org.opendaylight.controller</groupId>
-        <artifactId>configuration</artifactId>
-        <version>${controller.version}</version>
-      </dependency>
       <dependency>
         <groupId>org.opendaylight.controller</groupId>
         <artifactId>configuration.implementation</artifactId>
               <artifactId>netty-timer-config</artifactId>
               <version>${config.version}</version>
           </dependency>
-
           <dependency>
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>configuration</artifactId>
index b162b9c400137255ee3baff545b369cfd348f8f3..a03518235b6521ba1c297a7b04ab8db87e0ed872 100644 (file)
@@ -17,7 +17,7 @@
     </scm>
 
     <artifactId>protocol-framework</artifactId>
-    <version>0.4.1-SNAPSHOT</version>
+    <version>0.5.0-SNAPSHOT</version>
     <description>Common protocol framework</description>
     <packaging>bundle</packaging>
     <name>${project.artifactId}</name>
diff --git a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/DeserializerException.java b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/DeserializerException.java
deleted file mode 100644 (file)
index 608e949..0000000
+++ /dev/null
@@ -1,37 +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.protocol.framework;
-
-/**
- * Used when something occurs during parsing bytes to java objects.
- *
- * @deprecated This exception no longer carries any special meaning. Users
- * are advised to stop using it and define their own replacement.
- */
-@Deprecated
-public class DeserializerException extends Exception {
-
-    private static final long serialVersionUID = -2247000673438452870L;
-
-    /**
-     * Creates a deserializer exception.
-     * @param err string
-     */
-    public DeserializerException(final String err) {
-        super(err);
-    }
-
-    /**
-     * Creates a deserializer exception.
-     * @param err string
-     * @param e underlying exception
-     */
-    public DeserializerException(final String err, final Throwable e) {
-        super(err, e);
-    }
-}
diff --git a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/DocumentedException.java b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/DocumentedException.java
deleted file mode 100644 (file)
index 5e5f29e..0000000
+++ /dev/null
@@ -1,40 +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.protocol.framework;
-
-/**
- * Documented exception occurrs when an error is thrown that is documented
- * in any RFC or draft for the specific protocol.
- *
- * @deprecated This exception no longer carries any special meaning. Users
- * are advised to stop using it and define their own replacement.
- */
-@Deprecated
-public class DocumentedException extends Exception  {
-
-    private static final long serialVersionUID = -3727963789710833704L;
-
-    /**
-     * Creates a documented exception
-     * @param message string
-     */
-    public DocumentedException(final String message) {
-        super(message);
-    }
-
-    /**
-     * Creates a documented exception
-     * @param err string
-     * @param cause the cause (which is saved for later retrieval by the
-     * Throwable.getCause() method). (A null value is permitted, and indicates
-     * that the cause is nonexistent or unknown.)
-     */
-    public DocumentedException(final String err, final Exception cause) {
-        super(err, cause);
-    }
-}
diff --git a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ProtocolHandlerFactory.java b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ProtocolHandlerFactory.java
deleted file mode 100644 (file)
index 5c1377d..0000000
+++ /dev/null
@@ -1,36 +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.protocol.framework;
-
-import io.netty.channel.ChannelHandler;
-
-import com.google.common.base.Preconditions;
-
-/**
- * @deprecated This is an adaptor class for turning ProtocolMessageFactory into
- * Netty encoder/decoder. Use Netty-provided classes directly, by subclassing
- * {@link io.netty.handler.codec.ByteToMessageDecoder} or similar instead.
- */
-@Deprecated
-public class ProtocolHandlerFactory<T> {
-    private final ProtocolMessageEncoder<T> encoder;
-    protected final ProtocolMessageFactory<T> msgFactory;
-
-    public ProtocolHandlerFactory(final ProtocolMessageFactory<T> msgFactory) {
-        this.msgFactory = Preconditions.checkNotNull(msgFactory);
-        this.encoder = new ProtocolMessageEncoder<T>(msgFactory);
-    }
-
-    public ChannelHandler[] getEncoders() {
-        return new ChannelHandler[] { this.encoder };
-    }
-
-    public ChannelHandler[] getDecoders() {
-        return new ChannelHandler[] { new ProtocolMessageDecoder<T>(this.msgFactory) };
-    }
-}
diff --git a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ProtocolMessageDecoder.java b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ProtocolMessageDecoder.java
deleted file mode 100644 (file)
index 725e0a2..0000000
+++ /dev/null
@@ -1,55 +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.protocol.framework;
-
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.ByteBufUtil;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.codec.ByteToMessageDecoder;
-
-import java.util.List;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Preconditions;
-
-/**
- * @deprecated This is an adaptor class for turning ProtocolMessageFactory into Netty decoder. Use Netty-provided
- *             classes directly, by subclassing {@link io.netty.handler.codec.ByteToMessageDecoder} or similar instead.
- */
-@Deprecated
-public final class ProtocolMessageDecoder<T> extends ByteToMessageDecoder {
-
-    private static final Logger LOG = LoggerFactory.getLogger(ProtocolMessageDecoder.class);
-
-    private final ProtocolMessageFactory<T> factory;
-
-    public ProtocolMessageDecoder(final ProtocolMessageFactory<T> factory) {
-        this.factory = Preconditions.checkNotNull(factory);
-    }
-
-    @Override
-    protected void decode(final ChannelHandlerContext ctx, final ByteBuf in, final List<Object> out) throws Exception {
-        if (in.readableBytes() == 0) {
-            LOG.debug("No more content in incoming buffer.");
-            return;
-        }
-        in.markReaderIndex();
-        try {
-            LOG.trace("Received to decode: {}", ByteBufUtil.hexDump(in));
-            final byte[] bytes = new byte[in.readableBytes()];
-            in.readBytes(bytes);
-            out.add(this.factory.parse(bytes));
-        } catch (DeserializerException | DocumentedException e) {
-            LOG.debug("Failed to decode protocol message", e);
-            this.exceptionCaught(ctx, e);
-        }
-        in.discardReadBytes();
-    }
-}
diff --git a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ProtocolMessageEncoder.java b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ProtocolMessageEncoder.java
deleted file mode 100644 (file)
index 66378e7..0000000
+++ /dev/null
@@ -1,40 +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.protocol.framework;
-
-import io.netty.buffer.ByteBuf;
-import io.netty.channel.ChannelHandler.Sharable;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.codec.MessageToByteEncoder;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * @deprecated This is an adaptor class for turning ProtocolMessageFactory into Netty encoder. Use Netty-provided
- *             classes directly, by subclassing {@link io.netty.handler.codec.MessageToByteDecoder} or similar instead.
- */
-@Deprecated
-@Sharable
-public final class ProtocolMessageEncoder<T> extends MessageToByteEncoder<Object> {
-
-    private static final Logger LOG = LoggerFactory.getLogger(ProtocolMessageEncoder.class);
-
-    private final ProtocolMessageFactory<T> factory;
-
-    public ProtocolMessageEncoder(final ProtocolMessageFactory<T> factory) {
-        this.factory = factory;
-    }
-
-    @Override
-    protected void encode(final ChannelHandlerContext ctx, final Object msg, final ByteBuf out) throws Exception {
-        LOG.debug("Sent to encode : {}", msg);
-        final byte[] bytes = this.factory.put((T) msg);
-        out.writeBytes(bytes);
-    }
-}
diff --git a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ProtocolMessageFactory.java b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ProtocolMessageFactory.java
deleted file mode 100644 (file)
index 9b89dc3..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.protocol.framework;
-
-
-/**
- * Interface for factory for parsing and serializing protocol specific messages. Needs to be implemented by a protocol
- * specific message factory. The methods put/parse should delegate parsing to specific message parsers, e.g.
- * OpenMessageParser etc.
- *
- * @param <T> type of messages created by this factory
- *
- * @deprecated Interact with Netty 4.0 directly, by subclassing {@link io.netty.handler.codec.ByteToMessageCodec} or
- * similar.
- */
-@Deprecated
-public interface ProtocolMessageFactory<T> {
-
-    /**
-     * Parses message from byte array. Requires specific protocol message header object to parse the header.
-     *
-     * @param bytes byte array from which the message will be parsed
-     * @return List of specific protocol messages
-     * @throws DeserializerException if some parsing error occurs
-     * @throws DocumentedException if some documented error occurs
-     */
-    T parse(byte[] bytes) throws DeserializerException, DocumentedException;
-
-    /**
-     * Serializes protocol specific message to byte array.
-     *
-     * @param msg message to be serialized.
-     * @return byte array resulting message
-     */
-    byte[] put(T msg);
-}
diff --git a/opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/protocol/framework/ComplementaryTest.java b/opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/protocol/framework/ComplementaryTest.java
deleted file mode 100644 (file)
index 80e6ad9..0000000
+++ /dev/null
@@ -1,24 +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.protocol.framework;
-
-import static org.junit.Assert.assertEquals;
-
-import org.junit.Test;
-
-@Deprecated
-public class ComplementaryTest {
-
-    @Test
-    public void testExceptions() {
-        final DeserializerException de = new DeserializerException("some error");
-        final DocumentedException ee = new DocumentedException("some error");
-
-        assertEquals(de.getMessage(), ee.getMessage());
-    }
-}
index 5ab09bea11901fca52d5cd0c662f51cad1c17f10..28bd613648d31bfcb6072737b065ceaa07bf7390 100644 (file)
@@ -10,7 +10,7 @@ package org.opendaylight.controller.config.manager.impl;
 import org.opendaylight.yangtools.concepts.Identifier;
 
 public class TransactionIdentifier implements Identifier {
-
+    private static final long serialVersionUID = 1L;
     private final String name;
 
     public TransactionIdentifier(String name) {
index 06a582608610287fc543bdd4a4e362d3fc7d4bb3..16a0605cd4c39bc020a80a4da1f3870eb17109df 100644 (file)
@@ -15,11 +15,6 @@ import org.osgi.util.tracker.ServiceTrackerCustomizer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-/**
- * Every time factory is added or removed, blank transaction is triggered to handle
- * {@link org.opendaylight.controller.config.spi.ModuleFactory#getDefaultModules(org.opendaylight.controller.config.api.DependencyResolverFactory, org.osgi.framework.BundleContext)}
- * functionality.
- */
 public class BindingIndependentMappingServiceTracker implements ServiceTrackerCustomizer<BindingIndependentMappingService, BindingIndependentMappingService> {
     private static final Logger logger = LoggerFactory.getLogger(BindingIndependentMappingServiceTracker.class);
 
@@ -48,7 +43,7 @@ public class BindingIndependentMappingServiceTracker implements ServiceTrackerCu
         BindingIndependentMappingService service = ctx.getService(moduleFactoryServiceReference);
         this.service = service;
         CodecRegistry codecRegistry = service.getCodecRegistry();
-        logger.warn("Codec registry acquired {}", codecRegistry);
+        logger.debug("Codec registry acquired {}", codecRegistry);
         activator.initConfigManager(ctx, codecRegistry);
         return service;
     }
@@ -59,7 +54,7 @@ public class BindingIndependentMappingServiceTracker implements ServiceTrackerCu
     }
 
     @Override
-    public void removedService(ServiceReference<BindingIndependentMappingService> moduleFactoryServiceReference, BindingIndependentMappingService    o) {
+    public void removedService(ServiceReference<BindingIndependentMappingService> moduleFactoryServiceReference, BindingIndependentMappingService o) {
         // TODO crash
     }
 }
index d9bbeb4a2c9de5ab420eebbaaf702271e381b8a1..001af7525bb28a915e7b9ec0306bbd03046f24f1 100644 (file)
@@ -213,7 +213,6 @@ public abstract class AbstractConfigTest extends
         return mock(CodecRegistry.class);
     }
 
-
     public static interface BundleContextServiceRegistrationHandler {
 
        void handleServiceRegistration(Object serviceInstance);
diff --git a/opendaylight/config/config-module-archetype/pom.xml b/opendaylight/config/config-module-archetype/pom.xml
new file mode 100644 (file)
index 0000000..42c9105
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>config-subsystem</artifactId>
+    <version>0.2.4-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>config-module-archetype</artifactId>
+  <name>config-module-archetype</name>
+  <description>Archetype for new module managed by configuration subsystem</description>
+
+</project>
diff --git a/opendaylight/config/config-module-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml b/opendaylight/config/config-module-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml
new file mode 100644 (file)
index 0000000..fc30b4d
--- /dev/null
@@ -0,0 +1,46 @@
+<archetype>
+    <id>config-module-archetype</id>
+
+    <allowPartial>true</allowPartial>
+
+    <requiredProperties>
+        <requiredProperty key="module-name">
+        </requiredProperty>
+        <requiredProperty key="module-name-java-prefix">
+        </requiredProperty>
+        <requiredProperty key="module-implementation-name">
+            <defaultValue>impl</defaultValue>
+        </requiredProperty>
+        <requiredProperty key="config-api-yang-revision">
+            <defaultValue>2013-04-05</defaultValue>
+        </requiredProperty>
+        <requiredProperty key="config-api-version">
+            <defaultValue>0.2.4-SNAPSHOT</defaultValue>
+        </requiredProperty>
+        <requiredProperty key="yang-maven-plugin-version">
+            <defaultValue>0.6.2-SNAPSHOT</defaultValue>
+        </requiredProperty>
+        <requiredProperty key="revision">
+            <defaultValue>2014-01-31</defaultValue>
+        </requiredProperty>
+        <requiredProperty key="service-java-class">
+            <defaultValue>java.lang.AutoCloseable</defaultValue>
+        </requiredProperty>
+        <requiredProperty key="maven-bundle-plugin-version">
+            <defaultValue>2.4.0</defaultValue>
+        </requiredProperty>
+        <requiredProperty key="yang-namespace-mapping-from">
+            <defaultValue>urn:opendaylight:params:xml:ns:yang:controller</defaultValue>
+        </requiredProperty>
+        <requiredProperty key="yang-namespace-mapping-to">
+            <defaultValue>org.opendaylight.controller.config.yang</defaultValue>
+        </requiredProperty>
+
+    </requiredProperties>
+
+    <fileSets>
+        <fileSet filtered="true" encoding="UTF-8">
+            <directory>src/main/yang</directory>
+        </fileSet>
+    </fileSets>
+</archetype>
diff --git a/opendaylight/config/config-module-archetype/src/main/resources/archetype-resources/pom.xml b/opendaylight/config/config-module-archetype/src/main/resources/archetype-resources/pom.xml
new file mode 100644 (file)
index 0000000..d1c371d
--- /dev/null
@@ -0,0 +1,104 @@
+<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/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>${groupId}</groupId>
+  <artifactId>${artifactId}</artifactId>
+  <version>${version}</version>
+  <packaging>bundle</packaging>
+
+    <properties>
+        <jmxGeneratorPath>${project.build.directory}/generated-sources/config</jmxGeneratorPath>
+        <config.version>${config-api-version}</config.version>
+        <maven.bundle.version>${maven-bundle-plugin-version}</maven.bundle.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>config-api</artifactId>
+            <version>${config.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.opendaylight.yangtools</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+                <version>${yang-maven-plugin-version}</version>
+                <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>
+                                            ${yang-namespace-mapping-from}==${yang-namespace-mapping-to}
+                                        </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>
+
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <version>${maven.bundle.version}</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+                        <Export-Package>
+                            ${yang-namespace-mapping-to}.${module-name},
+                        </Export-Package>
+                        <Import-Package>
+                            *
+                        </Import-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+
+
+        </plugins>
+    </build>
+</project>
diff --git a/opendaylight/config/config-module-archetype/src/main/resources/archetype-resources/src/main/yang/__module-name__-impl.yang b/opendaylight/config/config-module-archetype/src/main/resources/archetype-resources/src/main/yang/__module-name__-impl.yang
new file mode 100644 (file)
index 0000000..8c1dab1
--- /dev/null
@@ -0,0 +1,54 @@
+// vi: set smarttab et sw=4 tabstop=4:
+module ${module-name}-${module-implementation-name} {
+
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:config:${module-name}:${module-implementation-name}";
+    prefix "${module-name}-${module-implementation-name}";
+
+    import config { prefix config; revision-date ${config-api-yang-revision}; }
+    import ${module-name} { prefix ${module-name}; revision-date ${revision}; }
+
+    description
+        "This module contains the base YANG definitions for
+        ${module-name} ${module-implementation-name} implementation.";
+
+    revision "${revision}" {
+        description
+            "Initial revision.";
+    }
+
+    // This is the definition of a service implementation
+    identity ${module-name}-${module-implementation-name} {
+            base config:module-type;
+            config:provided-service ${module-name}:${module-name};
+            config:java-name-prefix ${module-name-java-prefix};
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case ${module-name}-${module-implementation-name} {
+            when "/config:modules/config:module/config:type = '${module-name}-${module-implementation-name}'";
+
+            leaf simple-attribute {
+                type uint32;
+            }
+
+            container dto-attribute {
+                leaf inner-attribute {
+                    type string;
+                }
+            }
+
+            // Dependency attribute demonstration, the config:required-identity points to a service type
+            // In this case it is the same service type as this implementation provides: ${module-name}
+            container dependency-attribute {
+                uses config:service-ref {
+                    refine type {
+                        mandatory false;
+                        config:required-identity ${module-name}:${module-name};
+                    }
+                }
+            }
+
+        }
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/config/config-module-archetype/src/main/resources/archetype-resources/src/main/yang/__module-name__.yang b/opendaylight/config/config-module-archetype/src/main/resources/archetype-resources/src/main/yang/__module-name__.yang
new file mode 100644 (file)
index 0000000..2afc91e
--- /dev/null
@@ -0,0 +1,27 @@
+// vi: set smarttab et sw=4 tabstop=4:
+module ${module-name} {
+
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:config:${module-name}";
+    prefix "${module-name}";
+
+    import config { prefix config; revision-date ${config-api-yang-revision}; }
+
+    description
+        "This module contains the base YANG definitions for
+        ${module-name} services.";
+
+    revision "${revision}" {
+        description
+            "Initial revision.";
+    }
+
+    // This is the definition of a service
+    identity ${module-name} {
+
+        base "config:service-type";
+
+        // TODO modify the java class
+        config:java-class " ${service-java-class}";
+    }
+}
\ No newline at end of file
index 29d623274c907b914fe01b2180d27e0657f06f42..a0ccdb8e2e883294a57c75d3daf47c1c12ef1a2e 100644 (file)
@@ -8,6 +8,7 @@
 package org.opendaylight.controller.config.persist.storage.file.xml.model;
 
 final class PersistException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
 
     public PersistException(String s, Exception e) {
         super(s, e);
index 4c99c7770a4e3701719e9577fb5ccca7991c5924..13043458c0d097d0f6e936343480e77b63ad47be 100644 (file)
@@ -47,7 +47,7 @@ public class ConfigRegistryClientsTest {
     @Test
     public void testLookupRuntimeBeans() throws Exception {
         Set<ObjectName> jmxLookup = lookupRuntimeBeans(jmxRegistryClient);
-        assertEquals(Sets.newHashSet(testingRegistry.run2, testingRegistry.run1, testingRegistry.run3), jmxLookup);
+        assertEquals(Sets.newHashSet(TestingConfigRegistry.run2, TestingConfigRegistry.run1, TestingConfigRegistry.run3), jmxLookup);
     }
 
     private Set<ObjectName> lookupRuntimeBeans(ConfigRegistryClient client)
@@ -67,13 +67,13 @@ public class ConfigRegistryClientsTest {
                 jmxRegistryClient, TestingConfigRegistry.moduleName1,
                 TestingConfigRegistry.instName1);
         assertEquals(1, jmxLookup.size());
-        assertEquals(Sets.newHashSet(testingRegistry.run2), jmxLookup);
+        assertEquals(Sets.newHashSet(TestingConfigRegistry.run2), jmxLookup);
 
         jmxLookup = clientLookupRuntimeBeansWithModuleAndInstance(
                 jmxRegistryClient, TestingConfigRegistry.moduleName2,
                 TestingConfigRegistry.instName2);
         assertEquals(1, jmxLookup.size());
-        assertEquals(Sets.newHashSet(testingRegistry.run3), jmxLookup);
+        assertEquals(Sets.newHashSet(TestingConfigRegistry.run3), jmxLookup);
 
         jmxLookup = clientLookupRuntimeBeansWithModuleAndInstance(
                 jmxRegistryClient, TestingConfigRegistry.moduleName1,
index dbf8654d6e6ea15a3349688b072ce649bc292a58..80621a4d449b0a2ccdee94ec865a8744f437735d 100644 (file)
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!-- vi: set et smarttab sw=4 tabstop=4: -->
-<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">
+<!-- vi: set et smarttab sw=4 tabstop=4: --><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>
@@ -44,6 +43,7 @@
         <module>yang-test-plugin</module>
         <module>shutdown-api</module>
         <module>shutdown-impl</module>
+        <module>config-module-archetype</module>
     </modules>
 
     <profiles>
                                         </goals>
                                     </pluginExecutionFilter>
                                     <action>
-                                        <ignore />
+                                        <ignore/>
                                     </action>
                                 </pluginExecution>
                             </pluginExecutions>
             </plugins>
         </pluginManagement>
     </build>
-</project>
+</project>
\ No newline at end of file
index 2ae70562cfcf04c996a9d0de3f925cf3c2b4f69e..ec2d9853390b69a835e9a1e8d638c432dee07695 100644 (file)
@@ -10,7 +10,7 @@ package org.opendaylight.controller.config.yangjmxgenerator.plugin.util;
 import org.opendaylight.yangtools.yang.common.QName;
 
 public class NameConflictException extends RuntimeException {
-
+    private static final long serialVersionUID = 1L;
     private static final String messageBlueprint = "Name conflict for name: %s, first defined in: %s, then defined in: %s";
     private final String conflictingName;
     private final QName secondParentQName;
index 14ec7e0fdc9bfae4b97dd5ffe2705f67834b0e61..1837bac2664bdfa9a96feb7f25435ac418d37dda 100644 (file)
@@ -100,12 +100,15 @@ public class SchemaContextTest extends AbstractYangTest {
 
     @Test
     public void testReadingIdentities_threadsJavaModule() {
-        Map<String /* identity name */, Optional<QName>> expectedIdentitiesToBases = new HashMap(){{
+        Map<String /* identity name */, Optional<QName>> expectedIdentitiesToBases = new HashMap<String, Optional<QName>>(){
+            private static final long serialVersionUID = 1L;
+
+        {
             put(ModuleMXBeanEntryTest.EVENTBUS_MXB_NAME, Optional.of(MODULE_TYPE_Q_NAME));
             put(ModuleMXBeanEntryTest.ASYNC_EVENTBUS_MXB_NAME, Optional.of(MODULE_TYPE_Q_NAME));
             put(ModuleMXBeanEntryTest.THREADFACTORY_NAMING_MXB_NAME, Optional.of(MODULE_TYPE_Q_NAME));
             put(ModuleMXBeanEntryTest.THREADPOOL_DYNAMIC_MXB_NAME, Optional.of(MODULE_TYPE_Q_NAME));
-            put("thread-rpc-context", Optional.absent());
+            put("thread-rpc-context", Optional.<QName>absent());
             put(ModuleMXBeanEntryTest.THREADPOOL_REGISTRY_IMPL_NAME, Optional.of(MODULE_TYPE_Q_NAME));
         }};
 
index 8e40260dbff1d5fc5eadbfbc5d665bb734132fc8..9c6e98e57115f4026e3901ee70b0cc5ae1d4083c 100644 (file)
         </dependency>
     </dependencies>
 
+
+
     <build>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>org.eclipse.m2e</groupId>
+                    <artifactId>lifecycle-mapping</artifactId>
+                    <version>1.0.0</version>
+                    <configuration>
+                        <lifecycleMappingMetadata>
+                            <pluginExecutions>
+                                <pluginExecution>
+                                    <pluginExecutionFilter>
+                                        <groupId>
+                                            org.opendaylight.controller
+                                        </groupId>
+                                        <artifactId>
+                                            yang-test-plugin
+                                        </artifactId>
+                                        <versionRange>
+                                            [0.2.3,)
+                                        </versionRange>
+                                        <goals>
+                                            <goal>
+                                                delete-sources
+                                            </goal>
+                                            <goal>
+                                                process-sources
+                                            </goal>
+                                        </goals>
+                                    </pluginExecutionFilter>
+                                    <action>
+                                        <ignore/>
+                                    </action>
+                                </pluginExecution>
+                            </pluginExecutions>
+                        </lifecycleMappingMetadata>
+                    </configuration>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+
         <plugins>
             <plugin>
                 <groupId>org.opendaylight.yangtools</groupId>
index 34542de896e904db4b4422cb4be4b05a83f57d30..7151e561b1d1845faedefb5a3db3da54d2ca25cd 100644 (file)
@@ -12,7 +12,7 @@ import java.io.Serializable;
 
 public abstract class ConfigurationObject implements Serializable {
     private static final long serialVersionUID = 1L;
-    private static final String DEFAULT_REGEX = "^[\\w-\\+\\*\\/\\.\\(\\)\\[\\]\\@]{1,256}$";
+    private static final String DEFAULT_REGEX = "^[\\w-=\\+\\*\\.\\(\\)\\[\\]\\@\\|\\:]{1,256}$";
     private static final String REGEX_PROP_NAME = "resourceNameRegularExpression";
     private static String regex;
 
@@ -31,7 +31,7 @@ public abstract class ConfigurationObject implements Serializable {
      *         resource name regular expression, false otherwise
      */
     protected boolean isValidResourceName(String name) {
-        return (name != null) ? name.matches(regex) : false;
+        return name != null && name.matches(regex);
     }
 
     /**
index 2123f6b9eb9c1004d6dcc2dd34cf26726168c153..ee571b83e1c9c4e919eb688f0f965ab633219b21 100644 (file)
@@ -13,4 +13,12 @@ package org.opendaylight.controller.configuration;
  * Container configuration service
  */
 public interface IConfigurationContainerService extends IConfigurationServiceCommon {
+
+    /**
+     * Bundle will call this function to ask ContainerConfigurationService to provide the
+     * directory location of container
+     *
+     * @return The path to active container directory
+     */
+    String getConfigurationRoot();
 }
index e4d55d11fb39e126d2dbb99f0ceb0cb6672d7069..4c0f3a2da5f08b409e6c751e9e8828359ce7e850 100644 (file)
@@ -9,6 +9,7 @@
 
 package org.opendaylight.controller.configuration.internal;
 
+import java.io.File;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.EnumSet;
@@ -25,6 +26,7 @@ import org.opendaylight.controller.clustering.services.IClusterServices;
 import org.opendaylight.controller.configuration.ConfigurationEvent;
 import org.opendaylight.controller.configuration.ConfigurationObject;
 import org.opendaylight.controller.configuration.IConfigurationAware;
+import org.opendaylight.controller.configuration.IConfigurationContainerService;
 import org.opendaylight.controller.configuration.IConfigurationService;
 import org.opendaylight.controller.sal.utils.GlobalConstants;
 import org.opendaylight.controller.sal.utils.IObjectReader;
@@ -46,7 +48,7 @@ public class ConfigurationService implements IConfigurationService, ICacheUpdate
     private static final Logger logger = LoggerFactory
             .getLogger(ConfigurationService.class);
     public static final String SAVE_EVENT_CACHE = "config.event.save";
-    private static final Object ROOT = GlobalConstants.STARTUPHOME.toString();
+    private static final String ROOT = GlobalConstants.STARTUPHOME.toString();
     private IClusterGlobalServices clusterServices;
     private ConcurrentMap <ConfigurationEvent, String> configEvent;
     private Set<IConfigurationAware> configurationAwareList = Collections
@@ -105,21 +107,66 @@ public class ConfigurationService implements IConfigurationService, ICacheUpdate
         return saveConfigurationsInternal();
     }
 
+
+    private List<String> getContainerDirectoryList() {
+        List<String> containerList = new ArrayList<String>();
+        for (IConfigurationAware configurationAware : this.configurationAwareList) {
+            if (configurationAware instanceof IConfigurationContainerService) {
+                String containerFilePath = ((ContainerConfigurationService)configurationAware).getConfigurationRoot();
+                containerList.add(containerFilePath);
+            }
+        }
+        return containerList;
+    }
+
+    private void createContainerDirectory(IConfigurationAware configurationAware) {
+        String containerFilePath = ((ContainerConfigurationService) configurationAware).getConfigurationRoot();
+        if (!new File(containerFilePath).exists()) {
+            boolean created = new File(containerFilePath).mkdir();
+            if (!created) {
+               logger.error("Failed to create startup config directory: {}", containerFilePath);
+            }
+        }
+    }
+
+    private void clearStaleContainerDirectories() {
+        List<String> activeContainers = getContainerDirectoryList();
+        for (File file : new File(ROOT).listFiles()) {
+            if (file.isDirectory() && !activeContainers.contains(file.toPath() + File.separator)) {
+                logger.trace("Removing directory for container {}", file.getName());
+                for (File innerFile : file.listFiles()) {
+                      innerFile.delete();
+                }
+                boolean removed = file.delete();
+                if (!removed) {
+                   logger.warn("Failed to remove stale directory: {}", file.getName());
+                }
+            }
+        }
+    }
+
+
     private Status saveConfigurationsInternal() {
         boolean success = true;
         for (IConfigurationAware configurationAware : configurationAwareList) {
+            if (configurationAware instanceof IConfigurationContainerService) {
+                // Create directory for new containers
+                createContainerDirectory(configurationAware);
+            }
             Status status = configurationAware.saveConfiguration();
             if (!status.isSuccess()) {
                 success = false;
-                logger.warn("Failed to save config for {}",
-                        configurationAware.getClass().getName());
+                logger.warn("Failed to save config for {}", configurationAware.getClass().getName());
             }
         }
+        // Remove startup directories of containers that were removed from
+        // the configuration but not saved
+        clearStaleContainerDirectories();
+
         if (success) {
             return new Status(StatusCode.SUCCESS);
         } else {
-            return new Status(StatusCode.INTERNALERROR,
-                    "Failed to Save All Configurations");
+            return new Status(StatusCode.INTERNALERROR, "Failed to Save All Configurations");
         }
     }
 
index 9c1d391daa7b8e80eec73ce454e30a6b768efe4d..3e067254edb721cd6e5b7adb109c1e96badbadb2 100644 (file)
@@ -9,7 +9,6 @@
 
 package org.opendaylight.controller.configuration.internal;
 
-import java.io.File;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Dictionary;
@@ -52,14 +51,10 @@ public class ContainerConfigurationService implements IConfigurationContainerSer
     private static final Logger logger = LoggerFactory.getLogger(ContainerConfigurationService.class);
     private IClusterContainerServices clusterServices;
     private ConcurrentMap <ConfigurationEvent, String> containerConfigEvent;
-    /*
-     * Collection containing the configuration objects.
-     * This is configuration world: container names (also the map key)
-     * are maintained as they were configured by user, same case
-     */
+    // Directory which contains the startup files for this container
+    private String root;
     private Set<IConfigurationContainerAware> configurationAwareList = Collections
             .synchronizedSet(new HashSet<IConfigurationContainerAware>());
-    private String root;
     private ObjectReader objReader;
     private ObjectWriter objWriter;
 
@@ -93,14 +88,9 @@ public class ContainerConfigurationService implements IConfigurationContainerSer
 
     void init(Component c) {
         Dictionary<?, ?> props = c.getServiceProperties();
-        String containerName = (props != null) ? (String) props.get("containerName") : GlobalConstants.DEFAULT.toString();
-        root = String.format("%s%s/", GlobalConstants.STARTUPHOME.toString(), containerName);
-        if (!new File(root).exists()) {
-            boolean created = new File(root).mkdir();
-            if (!created) {
-                logger.error("Failed to create startup config directory for container {}", containerName);
-            }
-        }
+        String containerName = (props != null) ? (String) props.get("containerName") :
+            GlobalConstants.DEFAULT.toString();
+        root =  String.format("%s%s/", GlobalConstants.STARTUPHOME.toString(), containerName);
     }
 
     public void start() {
@@ -119,17 +109,18 @@ public class ContainerConfigurationService implements IConfigurationContainerSer
      * Function called by the dependency manager before Container is Stopped and Destroyed.
      */
     public void containerStop() {
-        // Remove container directory along with its startup files
-        File[] files = new File(root).listFiles();
-        for (File file : files) {
-            file.delete();
-        }
-        new File(root).delete();
+        // Do nothing
+    }
+
+    @Override
+    public String getConfigurationRoot() {
+        return root;
     }
 
     @Override
     public Status saveConfiguration() {
         boolean success = true;
+
         for (IConfigurationContainerAware configurationAware : configurationAwareList) {
             logger.trace("Save Config triggered for {}", configurationAware.getClass().getSimpleName());
 
index ad897fd6899b01a2645aee018198fd0b8742129a..0fee183b67b8c1be06725b310c4111fbf3f9f8a8 100644 (file)
@@ -9,7 +9,6 @@
 
 package org.opendaylight.controller.containermanager.internal;
 
-import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.ObjectInputStream;
@@ -751,26 +750,6 @@ public class ContainerManager extends Authorization<String> implements IContaine
         return status;
     }
 
-    private void removeComponentsStartUpfiles(String containerName) {
-        String startupLocation = String.format("./%s", GlobalConstants.STARTUPHOME.toString());
-        String containerPrint = String.format("_%s.", containerName.toLowerCase(Locale.ENGLISH));
-
-        File directory = new File(startupLocation);
-        String[] fileList = directory.list();
-
-        logger.trace("Deleting startup configuration files for container {}", containerName);
-        if (fileList != null) {
-            for (String fileName : fileList) {
-                if (fileName.contains(containerPrint)) {
-                    String fullPath = String.format("%s/%s", startupLocation, fileName);
-                    File file = new File(fullPath);
-                    boolean done = file.delete();
-                    logger.trace("{} {}", (done ? "Deleted: " : "Failed to delete: "), fileName);
-                }
-            }
-        }
-    }
-
     /**
      * Create and initialize default all resource group and create association
      * with default well known users and profiles, if not already learnt from
@@ -1013,19 +992,6 @@ public class ContainerManager extends Authorization<String> implements IContaine
         notifyContainerModeChange(delete, notifyLocal);
         // Notify listeners
         notifyContainerAwareListeners(container, delete);
-
-        /*
-         * This is a quick fix until configuration service becomes the
-         * centralized configuration management place. Here container manager
-         * will remove the startup files for all the bundles that are present in
-         * the container being deleted. Do the cleanup here in Container manger
-         * as do not want to put this temporary code in Configuration manager
-         * yet which is ODL.
-         */
-        if (delete) {
-            // TODO: remove when Config Mgr takes over
-            removeComponentsStartUpfiles(containerName);
-        }
     }
 
     private void notifyContainerEntryChangeInternal(String containerName, List<NodeConnector> ncList, UpdateType update, boolean notifyLocal) {
index 28637bcf46d1f2ae64f7c9cde5c4ab8026f18f30..fca4936c7f13a62a095b95fcc2dbe5b26a7c196b 100644 (file)
           <groupId>org.opendaylight.controller</groupId>
           <artifactId>sal-broker-impl</artifactId>
           <version>${mdsal.version}</version>
+        </dependency>
+          <dependency>
+              <groupId>org.opendaylight.controller</groupId>
+              <artifactId>sal-remote</artifactId>
+              <version>${mdsal.version}</version>
+          </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-restconf-broker</artifactId>
+            <version>${mdsal.version}</version>
         </dependency>
         <dependency>
           <groupId>org.opendaylight.controller</groupId>
           <artifactId>concepts</artifactId>
           <version>${yangtools.version}</version>
         </dependency>
+          <dependency>
+              <groupId>org.opendaylight.yangtools</groupId>
+              <artifactId>restconf-client-api</artifactId>
+              <version>${yangtools.version}</version>
+          </dependency>
+          <dependency>
+              <groupId>org.opendaylight.yangtools</groupId>
+              <artifactId>restconf-client-impl</artifactId>
+              <version>${yangtools.version}</version>
+          </dependency>
 
         <!-- config-->
         <dependency>
       <groupId>io.netty</groupId>
       <artifactId>netty-common</artifactId>
     </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-codec-http</artifactId>
+    </dependency>
 
     <!-- testing dependencies I'm pretty sure we should trim -->
     <dependency>
index bce7dd30ba59de6c9707062f3fdeaf9f23a8141d..b94103fb1c7c9233bb417e93cc74d42bbef498e7 100644 (file)
@@ -331,7 +331,7 @@ public class ForwardingRulesManager implements
         for (FlowEntryInstall installEntry : toInstallSafe) {
 
             // Install and update database
-            Status ret = addEntriesInternal(installEntry, async);
+            Status ret = addEntryInternal(installEntry, async);
 
             if (ret.isSuccess()) {
                 oneSucceded = true;
@@ -494,7 +494,7 @@ public class ForwardingRulesManager implements
             }
             // Install new entries
             for (FlowEntryInstall newEntry : toInstallSafe) {
-                succeeded = this.addEntriesInternal(newEntry, async);
+                succeeded = this.addEntryInternal(newEntry, async);
             }
         } else {
             /*
@@ -554,7 +554,9 @@ public class ForwardingRulesManager implements
     /**
      * This is the function that modifies the final container flows merged
      * entries on the network node and update the database. It expects that all
-     * the validity checks are passed
+     * the validity checks are passed.
+     * This function is supposed to be called only on the controller on which
+     * the IFRM call is executed.
      *
      * @param currentEntries
      * @param newEntries
@@ -564,13 +566,13 @@ public class ForwardingRulesManager implements
      *         contain the unique id assigned to this request
      */
     private Status modifyEntryInternal(FlowEntryInstall currentEntries, FlowEntryInstall newEntries, boolean async) {
+        Status status = new Status(StatusCode.UNDEFINED);
         FlowEntryDistributionOrderFutureTask futureStatus =
                 distributeWorkOrder(currentEntries, newEntries, UpdateType.CHANGED);
         if (futureStatus != null) {
-            Status retStatus = new Status(StatusCode.UNDEFINED);
             try {
-                retStatus = futureStatus.get();
-                if (retStatus.getCode()
+                status = futureStatus.get();
+                if (status.getCode()
                         .equals(StatusCode.TIMEOUT)) {
                     // A timeout happened, lets cleanup the workMonitor
                     workMonitor.remove(futureStatus.getOrder());
@@ -580,30 +582,31 @@ public class ForwardingRulesManager implements
             } catch (ExecutionException e) {
                 log.error("", e);
             }
-            return retStatus;
         } else {
             // Modify the flow on the network node
-            Status status = async ? programmer.modifyFlowAsync(currentEntries.getNode(), currentEntries.getInstall()
-                    .getFlow(), newEntries.getInstall()
-                    .getFlow()) : programmer.modifyFlow(currentEntries.getNode(), currentEntries.getInstall()
-                    .getFlow(), newEntries.getInstall()
-                    .getFlow());
+            status = modifyEntryInHw(currentEntries, newEntries, async);
+        }
 
-            if (!status.isSuccess()) {
-                log.trace("SDN Plugin failed to program the flow: {}. The failure is: {}", newEntries.getInstall(),
-                        status.getDescription());
-                return status;
-            }
+        if (!status.isSuccess()) {
+            log.trace("{} SDN Plugin failed to program the flow: {}. The failure is: {}",
+                    (futureStatus != null) ? "Remote" : "Local", newEntries.getInstall(), status.getDescription());
+            return status;
+        }
 
-            log.trace("Modified {} => {}", currentEntries.getInstall(), newEntries.getInstall());
+        log.trace("Modified {} => {}", currentEntries.getInstall(), newEntries.getInstall());
 
-            // Update DB
-            newEntries.setRequestId(status.getRequestId());
-            updateSwViews(currentEntries, false);
-            updateSwViews(newEntries, true);
+        // Update DB
+        newEntries.setRequestId(status.getRequestId());
+        updateSwViews(currentEntries, false);
+        updateSwViews(newEntries, true);
 
-            return status;
-        }
+        return status;
+    }
+
+    private Status modifyEntryInHw(FlowEntryInstall currentEntries, FlowEntryInstall newEntries, boolean async) {
+        return async ? programmer.modifyFlowAsync(currentEntries.getNode(), currentEntries.getInstall().getFlow(),
+                newEntries.getInstall().getFlow()) : programmer.modifyFlow(currentEntries.getNode(), currentEntries
+                .getInstall().getFlow(), newEntries.getInstall().getFlow());
     }
 
     /**
@@ -672,6 +675,8 @@ public class ForwardingRulesManager implements
      * This is the function that removes the final container flows merged entry
      * from the network node and update the database. It expects that all the
      * validity checks are passed
+     * This function is supposed to be called only on the controller on which
+     * the IFRM call is executed.
      *
      * @param entry
      *            the flow entry to remove
@@ -681,13 +686,12 @@ public class ForwardingRulesManager implements
      *         contain the unique id assigned to this request
      */
     private Status removeEntryInternal(FlowEntryInstall entry, boolean async) {
+        Status status = new Status(StatusCode.UNDEFINED);
         FlowEntryDistributionOrderFutureTask futureStatus = distributeWorkOrder(entry, null, UpdateType.REMOVED);
         if (futureStatus != null) {
-            Status retStatus = new Status(StatusCode.UNDEFINED);
             try {
-                retStatus = futureStatus.get();
-                if (retStatus.getCode()
-                        .equals(StatusCode.TIMEOUT)) {
+                status = futureStatus.get();
+                if (status.getCode().equals(StatusCode.TIMEOUT)) {
                     // A timeout happened, lets cleanup the workMonitor
                     workMonitor.remove(futureStatus.getOrder());
                 }
@@ -696,28 +700,31 @@ public class ForwardingRulesManager implements
             } catch (ExecutionException e) {
                 log.error("", e);
             }
-            return retStatus;
         } else {
             // Mark the entry to be deleted (for CC just in case we fail)
             entry.toBeDeleted();
 
             // Remove from node
-            Status status = async ? programmer.removeFlowAsync(entry.getNode(), entry.getInstall()
-                    .getFlow()) : programmer.removeFlow(entry.getNode(), entry.getInstall()
-                    .getFlow());
-
-            if (!status.isSuccess()) {
-                log.trace("SDN Plugin failed to remove the flow: {}. The failure is: {}", entry.getInstall(),
-                        status.getDescription());
-                return status;
-            }
-            log.trace("Removed  {}", entry.getInstall());
-
-            // Update DB
-            updateSwViews(entry, false);
+            status = removeEntryInHw(entry, async);
+        }
 
+        if (!status.isSuccess()) {
+            log.trace("{} SDN Plugin failed to remove the flow: {}. The failure is: {}",
+                    (futureStatus != null) ? "Remote" : "Local", entry.getInstall(), status.getDescription());
             return status;
         }
+
+        log.trace("Removed  {}", entry.getInstall());
+
+        // Update DB
+        updateSwViews(entry, false);
+
+        return status;
+    }
+
+    private Status removeEntryInHw(FlowEntryInstall entry, boolean async) {
+        return async ? programmer.removeFlowAsync(entry.getNode(), entry.getInstall().getFlow()) : programmer
+                .removeFlow(entry.getNode(), entry.getInstall().getFlow());
     }
 
     /**
@@ -725,6 +732,8 @@ public class ForwardingRulesManager implements
      * on the network node and updates the database. It expects that all the
      * validity and conflict checks are passed. That means it does not check
      * whether this flow would conflict or overwrite an existing one.
+     * This function is supposed to be called only on the controller on which
+     * the IFRM call is executed.
      *
      * @param entry
      *            the flow entry to install
@@ -733,14 +742,13 @@ public class ForwardingRulesManager implements
      * @return the status of this request. In case of asynchronous call, it will
      *         contain the unique id assigned to this request
      */
-    private Status addEntriesInternal(FlowEntryInstall entry, boolean async) {
+    private Status addEntryInternal(FlowEntryInstall entry, boolean async) {
+        Status status = new Status(StatusCode.UNDEFINED);
         FlowEntryDistributionOrderFutureTask futureStatus = distributeWorkOrder(entry, null, UpdateType.ADDED);
         if (futureStatus != null) {
-            Status retStatus = new Status(StatusCode.UNDEFINED);
             try {
-                retStatus = futureStatus.get();
-                if (retStatus.getCode()
-                        .equals(StatusCode.TIMEOUT)) {
+                status = futureStatus.get();
+                if (status.getCode().equals(StatusCode.TIMEOUT)) {
                     // A timeout happened, lets cleanup the workMonitor
                     workMonitor.remove(futureStatus.getOrder());
                 }
@@ -749,27 +757,29 @@ public class ForwardingRulesManager implements
             } catch (ExecutionException e) {
                 log.error("", e);
             }
-            return retStatus;
         } else {
-            // Install the flow on the network node
-            Status status = async ? programmer.addFlowAsync(entry.getNode(), entry.getInstall()
-                    .getFlow()) : programmer.addFlow(entry.getNode(), entry.getInstall()
-                    .getFlow());
+            status = addEntryInHw(entry, async);
+        }
 
-            if (!status.isSuccess()) {
-                log.trace("SDN Plugin failed to program the flow: {}. The failure is: {}", entry.getInstall(),
-                        status.getDescription());
-                return status;
-            }
+        if (!status.isSuccess()) {
+            log.trace("{} SDN Plugin failed to program the flow: {}. The failure is: {}",
+                    (futureStatus != null) ? "Remote" : "Local", entry.getInstall(), status.getDescription());
+            return status;
+        }
+
+        log.trace("Added    {}", entry.getInstall());
 
-            log.trace("Added    {}", entry.getInstall());
+        // Update DB
+        entry.setRequestId(status.getRequestId());
+        updateSwViews(entry, true);
 
-            // Update DB
-            entry.setRequestId(status.getRequestId());
-            updateSwViews(entry, true);
+        return status;
+    }
 
-            return status;
-        }
+    private Status addEntryInHw(FlowEntryInstall entry, boolean async) {
+        // Install the flow on the network node
+        return async ? programmer.addFlowAsync(entry.getNode(), entry.getInstall().getFlow()) : programmer.addFlow(
+                entry.getNode(), entry.getInstall().getFlow());
     }
 
     /**
@@ -2526,13 +2536,13 @@ public class ForwardingRulesManager implements
                                         FlowEntryInstall feiNew = workOrder.get(fe);
                                         switch (fe.getUpType()) {
                                         case ADDED:
-                                            gotStatus = addEntriesInternal(feiCurrent, false);
+                                            gotStatus = addEntryInHw(feiCurrent, false);
                                             break;
                                         case CHANGED:
-                                            gotStatus = modifyEntryInternal(feiCurrent, feiNew, false);
+                                            gotStatus = modifyEntryInHw(feiCurrent, feiNew, false);
                                             break;
                                         case REMOVED:
-                                            gotStatus = removeEntryInternal(feiCurrent, false);
+                                            gotStatus = removeEntryInHw(feiCurrent, false);
                                             break;
                                         }
                                         // Remove the Order
index 9e2123c6cd63cfd611f768ec49d2a04785a57864..b8b54b45ba8d10cac4cea25e4f0139bb2ee1c5f1 100644 (file)
@@ -61,4 +61,19 @@ public class IPHostId implements IHostId, Serializable {
         return new IPHostId(addr);
     }
 
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("IP=[");
+        if (this.ipAddress != null) {
+            builder.append(this.ipAddress.getHostAddress());
+        }
+        builder.append("]");
+        return (builder.toString());
+    }
 }
index 4ab84eb653c02bd563f413c92d32cd0674cb93d1..e10c5d1a78310e5bc1f81393a7899ec4aefab0c2 100644 (file)
@@ -80,4 +80,24 @@ public class IPMacHostId implements IHostId, Serializable {
         return new IPMacHostId(ip, mac);
     }
 
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("IP=[");
+        if (this.ipAddress != null) {
+            builder.append(this.ipAddress.getHostAddress());
+        }
+        builder.append("]")
+               .append("MAC=[");
+        if (this.macAddr != null) {
+            builder.append(this.macAddr.toString());
+        }
+        builder.append("]");
+        return (builder.toString());
+    }
 }
index 9cae4348b12121d7495cb06bec851987bb426b74..734a392bc121f7b33a20408908a3281193aec2aa 100644 (file)
@@ -948,6 +948,10 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw
         }
     }
 
+    /*
+     * This thread runs every 4 seconds
+     */
+
     class OutStandingARPHandler extends TimerTask {
         @Override
         public void run() {
@@ -955,53 +959,55 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw
                 return;
             }
             ARPPending arphost;
-            /* This routine runs every 4 seconds */
-            logger.trace("Number of Entries in ARP Pending/Failed Lists: ARPPendingList = {}, failedARPReqList = {}",
-                    ARPPendingList.size(), failedARPReqList.size());
-            for (Entry<IHostId, ARPPending> entry : ARPPendingList.entrySet()) {
-                arphost = entry.getValue();
-
-                if (hostsDB.containsKey(arphost.getHostId())) {
-                    // this host is already learned, shouldn't be in
-                    // ARPPendingList
-                    // Remove it and continue
-                    logger.warn("Learned Host {} found in ARPPendingList", decodeIPFromId(arphost.getHostId()));
-                    ARPPendingList.remove(entry.getKey());
-                    continue;
-                }
-                if (arphost.getSent_count() < hostRetryCount) {
-                    /*
-                     * No reply has been received of first ARP Req, send the
-                     * next one. Before sending the ARP, check if ARPHandler is
-                     * available or not
-                     */
-                    if (hostFinder == null) {
-                        logger.warn("ARPHandler Services are not available for Outstanding ARPs");
+            try {
+                for (Entry<IHostId, ARPPending> entry : ARPPendingList.entrySet()) {
+                    arphost = entry.getValue();
+
+                    if (hostsDB.containsKey(arphost.getHostId())) {
+                        // this host is already learned, shouldn't be in
+                        // ARPPendingList
+                        // Remove it and continue
+                        logger.warn("Learned Host {} found in ARPPendingList", decodeIPFromId(arphost.getHostId()));
+                        ARPPendingList.remove(entry.getKey());
                         continue;
                     }
-                    for (IHostFinder hf : hostFinder) {
-                        hf.find(decodeIPFromId(arphost.getHostId()));
-                    }
-                    arphost.sent_count++;
-                    logger.debug("ARP Sent from ARPPending List, IP: {}", decodeIPFromId(arphost.getHostId()));
-                } else if (arphost.getSent_count() >= hostRetryCount) {
-                    /*
-                     * ARP requests have been sent without receiving a reply,
-                     * remove this from the pending list
-                     */
-                    ARPPendingList.remove(entry.getKey());
-                    logger.debug("ARP reply not received after multiple attempts, removing from Pending List IP: {}",
-                            decodeIPFromId(arphost.getHostId()));
-                    /*
-                     * Add this host to a different list which will be processed
-                     * on link up events
-                     */
-                    logger.debug("Adding the host to FailedARPReqList IP: {}", decodeIPFromId(arphost.getHostId()));
-                    failedARPReqList.put(entry.getKey(), arphost);
+                    if (arphost.getSent_count() < hostRetryCount) {
+                        /*
+                         * No reply has been received of first ARP Req, send the
+                         * next one. Before sending the ARP, check if ARPHandler
+                         * is available or not
+                         */
+                        if (hostFinder == null) {
+                            logger.warn("ARPHandler Services are not available for Outstanding ARPs");
+                            continue;
+                        }
+                        for (IHostFinder hf : hostFinder) {
+                            hf.find(decodeIPFromId(arphost.getHostId()));
+                        }
+                        arphost.sent_count++;
+                        logger.debug("ARP Sent from ARPPending List, IP: {}", decodeIPFromId(arphost.getHostId()));
+                    } else if (arphost.getSent_count() >= hostRetryCount) {
+                        /*
+                         * ARP requests have been sent without receiving a
+                         * reply, remove this from the pending list
+                         */
+                        ARPPendingList.remove(entry.getKey());
+                        logger.debug(
+                                "ARP reply not received after multiple attempts, removing from Pending List IP: {}",
+                                decodeIPFromId(arphost.getHostId()));
+                        /*
+                         * Add this host to a different list which will be
+                         * processed on link up events
+                         */
+                        logger.debug("Adding the host to FailedARPReqList IP: {}", decodeIPFromId(arphost.getHostId()));
+                        failedARPReqList.put(entry.getKey(), arphost);
 
-                } else {
-                    logger.error("Inavlid arp_sent count for entry: {}", entry);
+                    } else {
+                        logger.error("Inavlid arp_sent count for entry: {}", entry);
+                    }
                 }
+            } catch (IllegalStateException e) {
+                logger.debug("IllegalStateException Received by OutStandingARPHandler from: {}", e.getMessage());
             }
         }
     }
@@ -1009,10 +1015,10 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw
     private class ARPRefreshHandler extends TimerTask {
         @Override
         public void run() {
-            if (stopping) {
+            if ((clusterContainerService != null) && !clusterContainerService.amICoordinator()) {
                 return;
             }
-            if ((clusterContainerService != null) && !clusterContainerService.amICoordinator()) {
+            if (stopping) {
                 return;
             }
             if (!hostRefresh) {
@@ -1026,49 +1032,54 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw
                 logger.error("ARPRefreshHandler(): hostsDB is not allocated yet:");
                 return;
             }
-            for (Entry<IHostId, HostNodeConnector> entry : hostsDB.entrySet()) {
-                HostNodeConnector host = entry.getValue();
-                if (host.isStaticHost()) {
-                    /* this host was learned via API3, don't age it out */
-                    continue;
-                }
-
-                short arp_cntdown = host.getArpSendCountDown();
-                arp_cntdown--;
-                if (arp_cntdown > hostRetryCount) {
-                    host.setArpSendCountDown(arp_cntdown);
-                } else if (arp_cntdown <= 0) {
-                    /*
-                     * No ARP Reply received in last 2 minutes, remove this host
-                     * and inform applications
-                     */
-                    removeKnownHost(entry.getKey());
-                    notifyHostLearnedOrRemoved(host, false);
-                } else if (arp_cntdown <= hostRetryCount) {
-                    /*
-                     * Use the services of arphandler to check if host is still
-                     * there
-                     */
-                    if (logger.isTraceEnabled()) {
-                        logger.trace(
-                                "ARP Probing ({}) for {}({})",
-                                new Object[] { arp_cntdown, host.getNetworkAddress().getHostAddress(),
-                                        HexEncode.bytesToHexString(host.getDataLayerAddressBytes()) });
+            try {
+                for (Entry<IHostId, HostNodeConnector> entry : hostsDB.entrySet()) {
+                    HostNodeConnector host = entry.getValue();
+                    if (host.isStaticHost()) {
+                        /* this host was learned via API3, don't age it out */
+                        continue;
                     }
-                    host.setArpSendCountDown(arp_cntdown);
-                    if (hostFinder == null) {
+
+                    short arp_cntdown = host.getArpSendCountDown();
+                    arp_cntdown--;
+                    if (arp_cntdown > hostRetryCount) {
+                        host.setArpSendCountDown(arp_cntdown);
+                    } else if (arp_cntdown <= 0) {
                         /*
-                         * If hostfinder is not available, then can't send the
-                         * probe. However, continue the age out the hosts since
-                         * we don't know if the host is indeed out there or not.
+                         * No ARP Reply received in last 2 minutes, remove this
+                         * host and inform applications
                          */
-                        logger.trace("ARPHandler is not avaialable, can't send the probe");
-                        continue;
-                    }
-                    for (IHostFinder hf : hostFinder) {
-                        hf.probe(host);
+                        removeKnownHost(entry.getKey());
+                        notifyHostLearnedOrRemoved(host, false);
+                    } else if (arp_cntdown <= hostRetryCount) {
+                        /*
+                         * Use the services of arphandler to check if host is
+                         * still there
+                         */
+                        if (logger.isTraceEnabled()) {
+                            logger.trace(
+                                    "ARP Probing ({}) for {}({})",
+                                    new Object[] { arp_cntdown, host.getNetworkAddress().getHostAddress(),
+                                            HexEncode.bytesToHexString(host.getDataLayerAddressBytes()) });
+                        }
+                        host.setArpSendCountDown(arp_cntdown);
+                        if (hostFinder == null) {
+                            /*
+                             * If hostfinder is not available, then can't send
+                             * the probe. However, continue the age out the
+                             * hosts since we don't know if the host is indeed
+                             * out there or not.
+                             */
+                            logger.trace("ARPHandler is not avaialable, can't send the probe");
+                            continue;
+                        }
+                        for (IHostFinder hf : hostFinder) {
+                            hf.probe(host);
+                        }
                     }
                 }
+            } catch (IllegalStateException e) {
+                logger.debug("IllegalStateException  Received by ARPRefreshHandler from: {}", e.getMessage());
             }
         }
     }
index 0fd26dbbe358ba49992214168e71bb05565b4335..3ceb5b181283468dea7500acd50b74ee90a6d431 100644 (file)
@@ -1,55 +1,71 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-  <modelVersion>4.0.0</modelVersion>
-  <parent>
-    <groupId>org.opendaylight.controller</groupId>
-    <artifactId>commons.opendaylight</artifactId>
-    <version>1.4.2-SNAPSHOT</version>
-    <relativePath>../../commons/opendaylight</relativePath>
-  </parent>
-  <scm>
-    <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
-    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
-    <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main</url>
-    <tag>HEAD</tag>
-  </scm>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>commons.opendaylight</artifactId>
+        <version>1.4.2-SNAPSHOT</version>
+        <relativePath>../../commons/opendaylight</relativePath>
+    </parent>
+    <scm>
+        <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+        <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+        <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main</url>
+        <tag>HEAD</tag>
+    </scm>
 
-  <artifactId>logging.bridge</artifactId>
-  <version>0.4.2-SNAPSHOT</version>
-  <packaging>bundle</packaging>
+    <artifactId>logging.bridge</artifactId>
+    <version>0.4.2-SNAPSHOT</version>
+    <packaging>bundle</packaging>
 
-  <dependencies>
-    <dependency>
-      <groupId>org.slf4j</groupId>
-      <artifactId>slf4j-api</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>equinoxSDK381</groupId>
-      <artifactId>org.eclipse.osgi</artifactId>
-    </dependency>
-  </dependencies>
+    <dependencies>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>equinoxSDK381</groupId>
+            <artifactId>org.eclipse.osgi</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>mockito-configuration</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
 
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <version>${bundle.plugin.version}</version>
-        <extensions>true</extensions>
-        <configuration>
-          <instructions>
-            <Import-Package>
-              org.slf4j,
-              org.osgi.framework,
-              org.osgi.service.log
-            </Import-Package>
-            <Bundle-Activator>
-              org.opendaylight.controller.logging.bridge.internal.Activator
-            </Bundle-Activator>
-          </instructions>
-          <manifestLocation>${project.basedir}/META-INF</manifestLocation>
-        </configuration>
-      </plugin>
-    </plugins>
-  </build>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <version>${bundle.plugin.version}</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Import-Package>
+                            org.slf4j,
+                            org.osgi.framework,
+                            org.osgi.service.log
+                        </Import-Package>
+                        <Bundle-Activator>
+                            org.opendaylight.controller.logging.bridge.internal.Activator
+                        </Bundle-Activator>
+                    </instructions>
+                    <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
 </project>
index 03719d567f5ac17776dbb4cfaddf04168e83a1c7..2f45c6f91b54abc8faf1a424b223f7f66dda4d4d 100644 (file)
@@ -26,19 +26,19 @@ public class LogListenerImpl implements LogListener {
         if (this.logger != null) {
             switch (entry.getLevel()) {
             case LogService.LOG_DEBUG:
-                this.logger.debug("Bundle:{} Message:{} Exception:{}", entry.getBundle()
+                this.logger.debug("Bundle:{} Message:{}", entry.getBundle()
                         .getSymbolicName(), entry.getMessage(), entry.getException());
                 break;
             case LogService.LOG_INFO:
-                this.logger.info("Bundle:{} Message:{} Exception:{}", entry.getBundle()
+                this.logger.info("Bundle:{} Message:{}", entry.getBundle()
                         .getSymbolicName(), entry.getMessage(), entry.getException());
                 break;
             case LogService.LOG_WARNING:
-                this.logger.warn("Bundle:{} Message:{} Exception:{}", entry.getBundle()
+                this.logger.warn("Bundle:{} Message:{}", entry.getBundle()
                         .getSymbolicName(), entry.getMessage(), entry.getException());
                 break;
             case LogService.LOG_ERROR:
-                this.logger.error("Bundle:{} Message:{} Exception:{}", entry.getBundle()
+                this.logger.error("Bundle:{} Message:{}", entry.getBundle()
                         .getSymbolicName(), entry.getMessage(), entry.getException());
                 break;
             }
diff --git a/opendaylight/logging/bridge/src/test/java/org/opendaylight/controller/logging/bridge/internal/LogListenerImplTest.java b/opendaylight/logging/bridge/src/test/java/org/opendaylight/controller/logging/bridge/internal/LogListenerImplTest.java
new file mode 100644 (file)
index 0000000..2490c39
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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.logging.bridge.internal;
+
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.log.LogEntry;
+import org.osgi.service.log.LogService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+public class LogListenerImplTest {
+    private static final Logger logger = LoggerFactory.getLogger(LogListenerImplTest.class);
+
+    @Test
+    public void test() {
+        LogListenerImpl tested = new LogListenerImpl(logger);
+        tested.logged(getEntry("m1", null));
+        tested.logged(getEntry("m2", new RuntimeException()));
+    }
+
+    private LogEntry getEntry(final String message, final Exception e) {
+        return new LogEntry() {
+            @Override
+            public Bundle getBundle() {
+                Bundle mock = mock(Bundle.class);
+                doReturn(null).when(mock).getSymbolicName();
+                return mock;
+            }
+
+            @Override
+            public ServiceReference getServiceReference() {
+                return null;
+            }
+
+            @Override
+            public int getLevel() {
+                return LogService.LOG_INFO;
+            }
+
+            @Override
+            public String getMessage() {
+                return message;
+            }
+
+            @Override
+            public Throwable getException() {
+                return e;
+            }
+
+            @Override
+            public long getTime() {
+                return 0;
+            }
+        };
+    }
+
+}
index a6fc4b0a23b609e30452bda7f8879b26ee436d06..a59c2c1636514dba415dc933774ec4c6d16353cf 100644 (file)
@@ -251,6 +251,7 @@ package class SalCompatibilityProvider implements BindingAwareProvider {
         topology.dataService = session.getSALService(DataProviderService)
         tpProvider.dataService = session.getSALService(DataProviderService)
 
+        inventory.start();
 
         tpProvider.start();
 
index fac12ee10d642f3acb0cad9057c699e10d9446fd..8a0874ee3123da1d919db48a5d32e476afb839fc 100644 (file)
@@ -199,9 +199,11 @@ class FlowProgrammerAdapter implements IPluginInFlowProgrammerService, SalFlowLi
     }
 
     private def Future<RpcResult<TransactionStatus>> internalModifyFlowAsync(Node node, Flow oldFlow, Flow newFlow, long rid) {
-        val flowId = getCache().remove(oldFlow);
+        var flowId = getCache().remove(oldFlow);
         if(flowId == null){
-            throw new IllegalArgumentException("oldFlow is unknown");
+            LOG.error("oldFlow not found in cache : " + oldFlow.hashCode);
+            flowId = UUID.randomUUID();
+            getCache().put(oldFlow, flowId);
         }
 
         getCache().put(newFlow, flowId);
@@ -212,7 +214,9 @@ class FlowProgrammerAdapter implements IPluginInFlowProgrammerService, SalFlowLi
     private def Future<RpcResult<TransactionStatus>> internalRemoveFlowAsync(Node node, Flow adflow, long rid){
         val flowId = getCache().remove(adflow);
         if(flowId == null){
-            throw new IllegalArgumentException("adflow is unknown");
+            //throw new IllegalArgumentException("adflow not found in cache : " + adflow.hashCode);
+            LOG.error("adflow not found in cache : " + adflow.hashCode);
+            return null;
         }
         val flow = adflow.toMDFlow(flowId.toString());
         val modification = this._dataBrokerService.beginTransaction();
@@ -227,6 +231,10 @@ class FlowProgrammerAdapter implements IPluginInFlowProgrammerService, SalFlowLi
     }
 
     private def toFutureStatus(Future<RpcResult<TransactionStatus>> future){
+        if(future == null){
+            return toStatus(true);
+        }
+
         try {
             val result = future.get();
             return toStatus(result);
index 60e43247c2810383f49b05a24699d14c1c1f355b..0c211fd0aa432547071654bda94233d69e2496c0 100644 (file)
@@ -11,6 +11,9 @@ import java.util.ArrayList
 import java.util.Collections
 import java.util.List
 import java.util.Set
+import java.util.ArrayList;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.Lock;
 import java.util.concurrent.CopyOnWriteArrayList;
 import org.opendaylight.controller.sal.binding.api.data.DataBrokerService
 import org.opendaylight.controller.sal.binding.api.data.DataProviderService
@@ -76,17 +79,18 @@ import static extension org.opendaylight.controller.sal.compatibility.NodeMappin
 import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader
 import java.util.concurrent.ConcurrentHashMap
 import java.util.Map
+import java.util.HashMap
 
 class InventoryAndReadAdapter implements IPluginInReadService,
-                                                                                        IPluginInInventoryService,
-                                                                                        OpendaylightInventoryListener,
-                                                                                        OpendaylightFlowStatisticsListener,
-                                                                                        OpendaylightFlowTableStatisticsListener,
-                                                                                        OpendaylightPortStatisticsListener {
+                                             IPluginInInventoryService,
+                                             OpendaylightInventoryListener,
+                                             OpendaylightFlowStatisticsListener,
+                                             OpendaylightFlowTableStatisticsListener,
+                                             OpendaylightPortStatisticsListener {
 
     private static val LOG = LoggerFactory.getLogger(InventoryAndReadAdapter);
 
-       private static val OPENFLOWV10_TABLE_ID = new Integer(0).shortValue;
+    private static val OPENFLOWV10_TABLE_ID = new Integer(0).shortValue;
     @Property
     DataBrokerService dataService;
 
@@ -111,21 +115,34 @@ class InventoryAndReadAdapter implements IPluginInReadService,
     @Property
     List<IPluginOutInventoryService> inventoryPublisher = new CopyOnWriteArrayList<IPluginOutInventoryService>();
 
-       def setInventoryPublisher(IPluginOutInventoryService listener){
+    private final InventoryNotificationProvider inventoryNotificationProvider = new InventoryNotificationProvider();
+
+    private final Map<InstanceIdentifier.PathArgument, List<InstanceIdentifier.PathArgument>> nodeToNodeConnectorsMap = new ConcurrentHashMap<InstanceIdentifier.PathArgument, List<InstanceIdentifier.PathArgument>>();
+
+    private final Lock nodeToNodeConnectorsLock = new ReentrantLock();
+
+
+    def start(){
+        inventoryNotificationProvider.dataProviderService = dataProviderService;
+        inventoryNotificationProvider.inventoryPublisher = inventoryPublisher;
+        // inventoryNotificationProvider.start();
+    }
+
+    def setInventoryPublisher(IPluginOutInventoryService listener){
         inventoryPublisher.add(listener);
-       }
+    }
 
-       def unsetInventoryPublisher(IPluginOutInventoryService listener){
+    def unsetInventoryPublisher(IPluginOutInventoryService listener){
         inventoryPublisher.remove(listener);
-       }
+    }
 
     def setReadPublisher(IPluginOutReadService listener) {
-       statisticsPublisher.add(listener);
+        statisticsPublisher.add(listener);
     }
     
     def unsetReadPublisher (IPluginOutReadService listener) {
-       if( listener != null)
-               statisticsPublisher.remove(listener);
+        if( listener != null)
+            statisticsPublisher.remove(listener);
     }
 
     protected def startChange() {
@@ -140,33 +157,33 @@ class InventoryAndReadAdapter implements IPluginInReadService,
     override readAllFlow(Node node, boolean cached) {
 
         val output = new ArrayList<FlowOnNode>();
-               val tableRef = InstanceIdentifier.builder(Nodes)
-                                                                               .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node))
-                                                       .augmentation(FlowCapableNode).child(Table, new TableKey(OPENFLOWV10_TABLE_ID)).toInstance();
-               
-               val it = this.startChange();
-               
-               val table= it.readConfigurationData(tableRef) as Table;
-               
-               if(table != null){
-                       LOG.trace("Number of flows installed in table 0 of node {} : {}",node,table.flow.size);
-                       
-                       for(flow : table.flow){
-                               
-                               val adsalFlow = ToSalConversionsUtils.toFlow(flow,node);
-                               val statsFromDataStore = flow.getAugmentation(FlowStatisticsData);
-                               
-                               if(statsFromDataStore != null){
-                                       val it = new FlowOnNode(adsalFlow);
-                                       byteCount =  statsFromDataStore.flowStatistics.byteCount.value.longValue;
-                                       packetCount = statsFromDataStore.flowStatistics.packetCount.value.longValue;
-                                       durationSeconds = statsFromDataStore.flowStatistics.duration.second.value.intValue;
-                                       durationNanoseconds = statsFromDataStore.flowStatistics.duration.nanosecond.value.intValue;
-                                       
-                                       output.add(it);
-                               }
-                       }
-               }
+        val tableRef = InstanceIdentifier.builder(Nodes)
+                                        .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node))
+                                        .augmentation(FlowCapableNode).child(Table, new TableKey(OPENFLOWV10_TABLE_ID)).toInstance();
+        
+        val it = this.startChange();
+        
+        val table= it.readConfigurationData(tableRef) as Table;
+        
+        if(table != null){
+            LOG.trace("Number of flows installed in table 0 of node {} : {}",node,table.flow.size);
+            
+            for(flow : table.flow){
+                
+                val adsalFlow = ToSalConversionsUtils.toFlow(flow,node);
+                val statsFromDataStore = flow.getAugmentation(FlowStatisticsData);
+                
+                if(statsFromDataStore != null){
+                    val it = new FlowOnNode(adsalFlow);
+                    byteCount =  statsFromDataStore.flowStatistics.byteCount.value.longValue;
+                    packetCount = statsFromDataStore.flowStatistics.packetCount.value.longValue;
+                    durationSeconds = statsFromDataStore.flowStatistics.duration.second.value.intValue;
+                    durationNanoseconds = statsFromDataStore.flowStatistics.duration.nanosecond.value.intValue;
+                    
+                    output.add(it);
+                }
+            }
+        }
         
         //TODO (main): Shell we send request to the switch? It will make async request to the switch.
         // Once plugin receive response, it will let adaptor know through onFlowStatisticsUpdate()
@@ -180,35 +197,35 @@ class InventoryAndReadAdapter implements IPluginInReadService,
     }
 
     override readAllNodeConnector(Node node, boolean cached) {
-       
-       val ret = new ArrayList<NodeConnectorStatistics>();
-               val nodeRef = InstanceIdentifier.builder(Nodes)
-                                                                       .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node))
-                                                                       .toInstance();
-               
-               val provider = this.startChange();
-               
-               val dsNode= provider.readConfigurationData(nodeRef) as org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
-               
-               if(dsNode != null){
-                       
-                       for (dsNodeConnector : dsNode.nodeConnector){
-                               val nodeConnectorRef = InstanceIdentifier.builder(Nodes)
-                                                                       .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node))
-                                                                       .child(NodeConnector, dsNodeConnector.key)
-                                                                       .toInstance();
-                               
-                               val nodeConnectorFromDS = provider.readConfigurationData(nodeConnectorRef) as NodeConnector;
-                               
-                               if(nodeConnectorFromDS != null){
-                                       val nodeConnectorStatsFromDs = nodeConnectorFromDS.getAugmentation(FlowCapableNodeConnectorStatisticsData) as FlowCapableNodeConnectorStatistics;
-                                       
-                                       ret.add(toNodeConnectorStatistics(nodeConnectorStatsFromDs.flowCapableNodeConnectorStatistics,dsNode.id,dsNodeConnector.id));
-                               }
-                       }
-               }
-
-               //TODO: Refer TODO (main)
+        
+        val ret = new ArrayList<NodeConnectorStatistics>();
+        val nodeRef = InstanceIdentifier.builder(Nodes)
+                                    .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node))
+                                    .toInstance();
+        
+        val provider = this.startChange();
+        
+        val dsNode= provider.readConfigurationData(nodeRef) as org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+        
+         if(dsNode != null){
+             
+             for (dsNodeConnector : dsNode.nodeConnector){
+                val nodeConnectorRef = InstanceIdentifier.builder(Nodes)
+                                    .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node))
+                                    .child(NodeConnector, dsNodeConnector.key)
+                                    .toInstance();
+                 
+                 val nodeConnectorFromDS = provider.readConfigurationData(nodeConnectorRef) as NodeConnector;
+                 
+                 if(nodeConnectorFromDS != null){
+                     val nodeConnectorStatsFromDs = nodeConnectorFromDS.getAugmentation(FlowCapableNodeConnectorStatisticsData) as FlowCapableNodeConnectorStatistics;
+                     
+                    ret.add(toNodeConnectorStatistics(nodeConnectorStatsFromDs.flowCapableNodeConnectorStatistics,dsNode.id,dsNodeConnector.id));
+                 }
+             }
+         }
+
+        //TODO: Refer TODO (main)
         val input = new GetAllNodeConnectorsStatisticsInputBuilder();
         input.setNode(node.toNodeRef);
         nodeConnectorStatisticsService.getAllNodeConnectorsStatistics(input.build());
@@ -216,23 +233,23 @@ class InventoryAndReadAdapter implements IPluginInReadService,
     }
 
     override readAllNodeTable(Node node, boolean cached) {
-       val ret = new ArrayList<NodeTableStatistics>();
-       
-               val dsFlowCapableNode= readFlowCapableNode(node.toNodeRef)
-               
-               if(dsFlowCapableNode != null){
-                       
-                       for (table : dsFlowCapableNode.table){
-                               
-                               val tableStats = table.getAugmentation(FlowTableStatisticsData);
-                               
-                               if(tableStats != null){
-                                       ret.add(toNodeTableStatistics(tableStats.flowTableStatistics,table.id,node));
-                               }
-                       }
-               }
-
-               //TODO: Refer TODO (main)
+        val ret = new ArrayList<NodeTableStatistics>();
+        
+        val dsFlowCapableNode= readFlowCapableNode(node.toNodeRef)
+        
+         if(dsFlowCapableNode != null){
+             
+             for (table : dsFlowCapableNode.table){
+                 
+                 val tableStats = table.getAugmentation(FlowTableStatisticsData);
+                 
+                 if(tableStats != null){
+                     ret.add(toNodeTableStatistics(tableStats.flowTableStatistics,table.id,node));
+                 }
+             }
+         }
+
+        //TODO: Refer TODO (main)
         val input = new GetFlowTablesStatisticsInputBuilder();
         input.setNode(node.toNodeRef);
         flowTableStatisticsService.getFlowTablesStatistics(input.build);
@@ -241,39 +258,39 @@ class InventoryAndReadAdapter implements IPluginInReadService,
 
     override readDescription(Node node, boolean cached) {
         return toNodeDescription(node.toNodeRef);
-       }
+    }
 
     override readFlow(Node node, Flow targetFlow, boolean cached) {
-               var FlowOnNode ret= null;
-               
-               val tableRef = InstanceIdentifier.builder(Nodes)
-                                                                               .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node))
-                                                       .augmentation(FlowCapableNode).child(Table, new TableKey(OPENFLOWV10_TABLE_ID)).toInstance();
-               
-               val it = this.startChange();
-               
-               val table= it.readConfigurationData(tableRef) as Table;
-               
-               if(table != null){
-                       LOG.trace("Number of flows installed in table 0 of node {} : {}",node,table.flow.size);
-                       
-                       for(mdsalFlow : table.flow){
-                               if(FromSalConversionsUtils.flowEquals(mdsalFlow, MDFlowMapping.toMDSalflow(targetFlow))){
-                                       val statsFromDataStore = mdsalFlow.getAugmentation(FlowStatisticsData);
-                                       
-                                       if(statsFromDataStore != null){
-                                               LOG.debug("Found matching flow in the data store flow table ");
-                                               val it = new FlowOnNode(targetFlow);
-                                               byteCount =  statsFromDataStore.flowStatistics.byteCount.value.longValue;
-                                               packetCount = statsFromDataStore.flowStatistics.packetCount.value.longValue;
-                                               durationSeconds = statsFromDataStore.flowStatistics.duration.second.value.intValue;
-                                               durationNanoseconds = statsFromDataStore.flowStatistics.duration.nanosecond.value.intValue;
-                                               
-                                               ret = it;
-                                       }
-                               }                       
-                       }
-               }
+        var FlowOnNode ret= null;
+        
+        val tableRef = InstanceIdentifier.builder(Nodes)
+                                        .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node))
+                                        .augmentation(FlowCapableNode).child(Table, new TableKey(OPENFLOWV10_TABLE_ID)).toInstance();
+        
+        val it = this.startChange();
+        
+        val table= it.readConfigurationData(tableRef) as Table;
+        
+        if(table != null){
+            LOG.trace("Number of flows installed in table 0 of node {} : {}",node,table.flow.size);
+            
+            for(mdsalFlow : table.flow){
+                if(FromSalConversionsUtils.flowEquals(mdsalFlow, MDFlowMapping.toMDSalflow(targetFlow))){
+                    val statsFromDataStore = mdsalFlow.getAugmentation(FlowStatisticsData);
+                    
+                    if(statsFromDataStore != null){
+                        LOG.debug("Found matching flow in the data store flow table ");
+                        val it = new FlowOnNode(targetFlow);
+                        byteCount =  statsFromDataStore.flowStatistics.byteCount.value.longValue;
+                        packetCount = statsFromDataStore.flowStatistics.packetCount.value.longValue;
+                        durationSeconds = statsFromDataStore.flowStatistics.duration.second.value.intValue;
+                        durationNanoseconds = statsFromDataStore.flowStatistics.duration.nanosecond.value.intValue;
+                        
+                        ret = it;
+                    }
+                }            
+            }
+        }
         
         //TODO: Refer TODO (main)
         val input = new GetFlowStatisticsFromFlowTableInputBuilder;
@@ -282,30 +299,30 @@ class InventoryAndReadAdapter implements IPluginInReadService,
         flowStatisticsService.getFlowStatisticsFromFlowTable(input.build)
         
         return ret;
-       
+        
     }
 
     override readNodeConnector(org.opendaylight.controller.sal.core.NodeConnector connector, boolean cached) {
-       var NodeConnectorStatistics  nodeConnectorStatistics = null;
-       
-               val nodeConnectorRef = InstanceIdentifier.builder(Nodes)
-                                                                       .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(connector.node))
-                                                                       .child(NodeConnector, InventoryMapping.toNodeConnectorKey(connector))
-                                                                       .toInstance();
-               val provider = this.startChange();
-                               
-               val nodeConnectorFromDS = provider.readConfigurationData(nodeConnectorRef) as NodeConnector;
-                               
-               if(nodeConnectorFromDS != null){
-                       val nodeConnectorStatsFromDs = nodeConnectorFromDS.getAugmentation(FlowCapableNodeConnectorStatisticsData) as FlowCapableNodeConnectorStatistics;
-                       if(nodeConnectorStatsFromDs != null) {
-                               nodeConnectorStatistics = toNodeConnectorStatistics(nodeConnectorStatsFromDs.flowCapableNodeConnectorStatistics,
-                                                                                                                                               InventoryMapping.toNodeKey(connector.node).id,
-                                                                                                                                               InventoryMapping.toNodeConnectorKey(connector).id);
-                       }
-               }
-
-               //TODO: Refer TODO (main)
+        var NodeConnectorStatistics  nodeConnectorStatistics = null;
+    
+        val nodeConnectorRef = InstanceIdentifier.builder(Nodes)
+                                    .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(connector.node))
+                                    .child(NodeConnector, InventoryMapping.toNodeConnectorKey(connector))
+                                    .toInstance();
+         val provider = this.startChange();
+                 
+         val nodeConnectorFromDS = provider.readConfigurationData(nodeConnectorRef) as NodeConnector;
+                 
+         if(nodeConnectorFromDS != null){
+            val nodeConnectorStatsFromDs = nodeConnectorFromDS.getAugmentation(FlowCapableNodeConnectorStatisticsData) as FlowCapableNodeConnectorStatistics;
+            if(nodeConnectorStatsFromDs != null) {
+                nodeConnectorStatistics = toNodeConnectorStatistics(nodeConnectorStatsFromDs.flowCapableNodeConnectorStatistics,
+                                                                        InventoryMapping.toNodeKey(connector.node).id,
+                                                                        InventoryMapping.toNodeConnectorKey(connector).id);
+            }
+        }
+
+        //TODO: Refer TODO (main)
         val input = new GetNodeConnectorStatisticsInputBuilder();
         input.setNode(connector.node.toNodeRef);
         input.setNodeConnectorId(InventoryMapping.toNodeConnectorKey(connector).id);
@@ -314,25 +331,25 @@ class InventoryAndReadAdapter implements IPluginInReadService,
     }
 
     override readNodeTable(NodeTable nodeTable, boolean cached) {
-       var NodeTableStatistics nodeStats = null
-       
-       val tableRef = InstanceIdentifier.builder(Nodes)
-                                                                               .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(nodeTable.node))
-                                                       .augmentation(FlowCapableNode).child(Table, new TableKey(nodeTable.ID as Short)).toInstance();
-               
-               val it = this.startChange();
-               
-               val table= it.readConfigurationData(tableRef) as Table;
-               
-               if(table != null){
-                       val tableStats = table.getAugmentation(FlowTableStatisticsData);
-                               
-                       if(tableStats != null){
-                               nodeStats =  toNodeTableStatistics(tableStats.flowTableStatistics,table.id,nodeTable.node);
-                       }
-               }
-
-               //TODO: Refer TODO (main)
+        var NodeTableStatistics nodeStats = null
+        
+        val tableRef = InstanceIdentifier.builder(Nodes)
+                                        .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(nodeTable.node))
+                                        .augmentation(FlowCapableNode).child(Table, new TableKey(nodeTable.ID as Short)).toInstance();
+        
+        val it = this.startChange();
+        
+        val table= it.readConfigurationData(tableRef) as Table;
+        
+        if(table != null){
+            val tableStats = table.getAugmentation(FlowTableStatisticsData);
+                 
+             if(tableStats != null){
+                 nodeStats =  toNodeTableStatistics(tableStats.flowTableStatistics,table.id,nodeTable.node);
+            }
+        }
+
+        //TODO: Refer TODO (main)
         val input = new GetFlowTablesStatisticsInputBuilder();
         input.setNode(nodeTable.node.toNodeRef);
         flowTableStatisticsService.getFlowTablesStatistics(input.build);
@@ -341,19 +358,22 @@ class InventoryAndReadAdapter implements IPluginInReadService,
     }
 
     override onNodeConnectorRemoved(NodeConnectorRemoved update) {
-        // NOOP
+        // Never received
     }
 
     override onNodeRemoved(NodeRemoved notification) {
         val properties = Collections.<org.opendaylight.controller.sal.core.Property>emptySet();
 
+        removeNodeConnectors(notification.nodeRef.value);
+
         publishNodeUpdate(notification.nodeRef.toADNode, UpdateType.REMOVED, properties);
     }
 
     override onNodeConnectorUpdated(NodeConnectorUpdated update) {
         var updateType = UpdateType.CHANGED;
-        if ( this._dataService.readOperationalData(update.nodeConnectorRef.value as InstanceIdentifier<? extends DataObject>) == null ){
+        if(!isKnownNodeConnector(update.nodeConnectorRef.value)){
             updateType = UpdateType.ADDED;
+            recordNodeConnector(update.nodeConnectorRef.value);
         }
 
         var nodeConnector = update.nodeConnectorRef.toADNodeConnector
@@ -369,16 +389,16 @@ class InventoryAndReadAdapter implements IPluginInReadService,
             updateType = UpdateType.ADDED;
         }
         publishNodeUpdate(notification.nodeRef.toADNode, updateType, notification.toADNodeProperties);
-        
-               //Notify the listeners of IPluginOutReadService
-        
+
+        //Notify the listeners of IPluginOutReadService
+
         for (statsPublisher : statisticsPublisher){
-                       val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
+            val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
             val description = notification.nodeRef.toNodeDescription
             if(description != null) {
-                         statsPublisher.descriptionStatisticsUpdated(nodeRef.toADNode,description);
-                       }
-               }
+              statsPublisher.descriptionStatisticsUpdated(nodeRef.toADNode,description);
+            }
+        }
     }
 
     override getNodeProps() {
@@ -461,50 +481,50 @@ class InventoryAndReadAdapter implements IPluginInReadService,
 
     private def toNodeConnectorStatistics(
         org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.NodeConnectorStatistics nodeConnectorStatistics, NodeId nodeId, NodeConnectorId nodeConnectorId) {
-               
-                       val it = new NodeConnectorStatistics();
-                       
-                       receivePacketCount = nodeConnectorStatistics.packets.received.longValue;
-                       transmitPacketCount = nodeConnectorStatistics.packets.transmitted.longValue;
-                       
-                       receiveByteCount = nodeConnectorStatistics.bytes.received.longValue;
-                       transmitByteCount = nodeConnectorStatistics.bytes.transmitted.longValue;
-                       
-                       receiveDropCount = nodeConnectorStatistics.receiveDrops.longValue;
-                       transmitDropCount = nodeConnectorStatistics.transmitDrops.longValue;
-                       
-                       receiveErrorCount = nodeConnectorStatistics.receiveErrors.longValue;
-                       transmitErrorCount = nodeConnectorStatistics.transmitErrors.longValue;
-                       
-                       receiveFrameErrorCount = nodeConnectorStatistics.receiveFrameError.longValue;
-                       receiveOverRunErrorCount = nodeConnectorStatistics.receiveOverRunError.longValue;
-                       receiveCRCErrorCount = nodeConnectorStatistics.receiveCrcError.longValue;
-                       collisionCount = nodeConnectorStatistics.collisionCount.longValue;
-                       
-                       val nodeConnectorRef = InstanceIdentifier.builder(Nodes)
-                                                               .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(nodeId))
-                                                               .child(NodeConnector,new NodeConnectorKey(nodeConnectorId)).toInstance;
-                       
-                       nodeConnector = NodeMapping.toADNodeConnector(new NodeConnectorRef(nodeConnectorRef));
-                       
-                       return it;
-    }
-
-       private def toNodeTableStatistics(
-               FlowTableStatistics tableStats,
-               Short tableId,Node node){
-               var it = new NodeTableStatistics();
-               
-               activeCount = tableStats.activeFlows.value.intValue;
-               lookupCount = tableStats.packetsLookedUp.value.intValue;
-               matchedCount = tableStats.packetsMatched.value.intValue;
-               name = tableId.toString;
-               nodeTable = new NodeTable(NodeMapping.MD_SAL_TYPE,tableId,node);
-               return it;
-       }
-       
-       private def toNodeDescription(NodeRef nodeRef){
-               val capableNode = readFlowCapableNode(nodeRef);
+            
+            val it = new NodeConnectorStatistics();
+            
+            receivePacketCount = nodeConnectorStatistics.packets.received.longValue;
+            transmitPacketCount = nodeConnectorStatistics.packets.transmitted.longValue;
+            
+            receiveByteCount = nodeConnectorStatistics.bytes.received.longValue;
+            transmitByteCount = nodeConnectorStatistics.bytes.transmitted.longValue;
+            
+            receiveDropCount = nodeConnectorStatistics.receiveDrops.longValue;
+            transmitDropCount = nodeConnectorStatistics.transmitDrops.longValue;
+            
+            receiveErrorCount = nodeConnectorStatistics.receiveErrors.longValue;
+            transmitErrorCount = nodeConnectorStatistics.transmitErrors.longValue;
+            
+            receiveFrameErrorCount = nodeConnectorStatistics.receiveFrameError.longValue;
+            receiveOverRunErrorCount = nodeConnectorStatistics.receiveOverRunError.longValue;
+            receiveCRCErrorCount = nodeConnectorStatistics.receiveCrcError.longValue;
+            collisionCount = nodeConnectorStatistics.collisionCount.longValue;
+            
+            val nodeConnectorRef = InstanceIdentifier.builder(Nodes)
+                                .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(nodeId))
+                                .child(NodeConnector,new NodeConnectorKey(nodeConnectorId)).toInstance;
+            
+            nodeConnector = NodeMapping.toADNodeConnector(new NodeConnectorRef(nodeConnectorRef));
+            
+            return it;
+    }
+
+    private def toNodeTableStatistics(
+        FlowTableStatistics tableStats,
+        Short tableId,Node node){
+        var it = new NodeTableStatistics();
+        
+        activeCount = tableStats.activeFlows.value.intValue;
+        lookupCount = tableStats.packetsLookedUp.value.intValue;
+        matchedCount = tableStats.packetsMatched.value.intValue;
+        name = tableId.toString;
+        nodeTable = new NodeTable(NodeMapping.MD_SAL_TYPE,tableId,node);
+        return it;
+    }
+    
+    private def toNodeDescription(NodeRef nodeRef){
+        val capableNode = readFlowCapableNode(nodeRef);
         if(capableNode !=null) {
             val it = new NodeDescription()
             manufacturer = capableNode.manufacturer
@@ -515,101 +535,148 @@ class InventoryAndReadAdapter implements IPluginInReadService,
             return it;
          }
          return null;
-       }
+    }
     
     
     def Edge toADEdge(Link link) {
         new Edge(link.source.toADNodeConnector,link.destination.toADNodeConnector)
     }
-       
-       /*
-        * OpendaylightFlowStatisticsListener interface implementation
-        */
-       override onAggregateFlowStatisticsUpdate(AggregateFlowStatisticsUpdate notification) {
+    
+    /*
+     * OpendaylightFlowStatisticsListener interface implementation
+     */
+    override onAggregateFlowStatisticsUpdate(AggregateFlowStatisticsUpdate notification) {
         //Ignoring this notification as there does not seem to be a way to bubble this up to AD-SAL
-       }
-       
-       override onFlowsStatisticsUpdate(FlowsStatisticsUpdate notification) {
-               
-               val adsalFlowsStatistics = new ArrayList<FlowOnNode>();
-               val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
-               
-               for(flowStats : notification.flowAndStatisticsMapList){
-                       if(flowStats.tableId == 0)
-                               adsalFlowsStatistics.add(toFlowOnNode(flowStats,nodeRef.toADNode));
-               }
-               
-               for (statsPublisher : statisticsPublisher){
-                       statsPublisher.nodeFlowStatisticsUpdated(nodeRef.toADNode,adsalFlowsStatistics);
-               }
-               
-       }
-       /*
-        * OpendaylightFlowTableStatisticsListener interface implementation
-        */     
-       override onFlowTableStatisticsUpdate(FlowTableStatisticsUpdate notification) {
-               var adsalFlowTableStatistics = new ArrayList<NodeTableStatistics>();
-               
-               for(stats : notification.flowTableAndStatisticsMap){
-                       if (stats.tableId.value == 0){
-                               val it = new NodeTableStatistics();
-                               activeCount = stats.activeFlows.value.intValue;
-                               lookupCount = stats.packetsLookedUp.value.longValue;
-                               matchedCount = stats.packetsMatched.value.longValue;
-                               
-                               adsalFlowTableStatistics.add(it);
-                       }
-               }
-               for (statsPublisher : statisticsPublisher){
-                       val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
-                       statsPublisher.nodeTableStatisticsUpdated(nodeRef.toADNode,adsalFlowTableStatistics);
-               }
-       }
-       
-       /*
-        * OpendaylightPortStatisticsUpdate interface implementation
-        */
-       override onNodeConnectorStatisticsUpdate(NodeConnectorStatisticsUpdate notification) {
-               
-               val adsalPortStatistics  = new ArrayList<NodeConnectorStatistics>();
-               
-               for(nodeConnectorStatistics : notification.nodeConnectorStatisticsAndPortNumberMap){
-                       adsalPortStatistics.add(toNodeConnectorStatistics(nodeConnectorStatistics,notification.id,nodeConnectorStatistics.nodeConnectorId));
-               }
-               
-               for (statsPublisher : statisticsPublisher){
-                       val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
-                       statsPublisher.nodeConnectorStatisticsUpdated(nodeRef.toADNode,adsalPortStatistics);
-               }
-               
-       }
-       
-       private static def toFlowOnNode (FlowAndStatisticsMapList flowAndStatsMap,Node node){
-               
-               val it = new FlowOnNode(ToSalConversionsUtils.toFlow(flowAndStatsMap,node));
-               
-               byteCount = flowAndStatsMap.byteCount.value.longValue;
-               packetCount = flowAndStatsMap.packetCount.value.longValue;
-               durationSeconds = flowAndStatsMap.duration.second.value.intValue;
-               durationNanoseconds = flowAndStatsMap.duration.nanosecond.value.intValue;
-               
-               return it;
-       }
-
-       override  getConfiguredNotConnectedNodes() {
+    }
+    
+    override onFlowsStatisticsUpdate(FlowsStatisticsUpdate notification) {
+        
+        val adsalFlowsStatistics = new ArrayList<FlowOnNode>();
+        val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
+        
+        for(flowStats : notification.flowAndStatisticsMapList){
+            if(flowStats.tableId == 0)
+                adsalFlowsStatistics.add(toFlowOnNode(flowStats,nodeRef.toADNode));
+        }
+        
+        for (statsPublisher : statisticsPublisher){
+            statsPublisher.nodeFlowStatisticsUpdated(nodeRef.toADNode,adsalFlowsStatistics);
+        }
+        
+    }
+    /*
+     * OpendaylightFlowTableStatisticsListener interface implementation
+     */    
+    override onFlowTableStatisticsUpdate(FlowTableStatisticsUpdate notification) {
+        var adsalFlowTableStatistics = new ArrayList<NodeTableStatistics>();
+        
+        for(stats : notification.flowTableAndStatisticsMap){
+            if (stats.tableId.value == 0){
+                val it = new NodeTableStatistics();
+                activeCount = stats.activeFlows.value.intValue;
+                lookupCount = stats.packetsLookedUp.value.longValue;
+                matchedCount = stats.packetsMatched.value.longValue;
+                
+                adsalFlowTableStatistics.add(it);
+            }
+        }
+        for (statsPublisher : statisticsPublisher){
+            val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
+            statsPublisher.nodeTableStatisticsUpdated(nodeRef.toADNode,adsalFlowTableStatistics);
+        }
+    }
+    
+    /*
+     * OpendaylightPortStatisticsUpdate interface implementation
+     */
+    override onNodeConnectorStatisticsUpdate(NodeConnectorStatisticsUpdate notification) {
+        
+        val adsalPortStatistics  = new ArrayList<NodeConnectorStatistics>();
+        
+        for(nodeConnectorStatistics : notification.nodeConnectorStatisticsAndPortNumberMap){
+            adsalPortStatistics.add(toNodeConnectorStatistics(nodeConnectorStatistics,notification.id,nodeConnectorStatistics.nodeConnectorId));
+        }
+        
+        for (statsPublisher : statisticsPublisher){
+            val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
+            statsPublisher.nodeConnectorStatisticsUpdated(nodeRef.toADNode,adsalPortStatistics);
+        }
+        
+    }
+    
+    private static def toFlowOnNode (FlowAndStatisticsMapList flowAndStatsMap,Node node){
+        
+        val it = new FlowOnNode(ToSalConversionsUtils.toFlow(flowAndStatsMap,node));
+        
+        byteCount = flowAndStatsMap.byteCount.value.longValue;
+        packetCount = flowAndStatsMap.packetCount.value.longValue;
+        durationSeconds = flowAndStatsMap.duration.second.value.intValue;
+        durationNanoseconds = flowAndStatsMap.duration.nanosecond.value.intValue;
+        
+        return it;
+    }
+
+    override  getConfiguredNotConnectedNodes() {
         return Collections.emptySet();
-       }
+    }
+
+
+    private def publishNodeUpdate(Node node, UpdateType updateType, Set<org.opendaylight.controller.sal.core.Property> properties){
+        for( publisher : inventoryPublisher){
+            publisher.updateNode(node, updateType, properties);
+        }
+    }
+
+    private def publishNodeConnectorUpdate(org.opendaylight.controller.sal.core.NodeConnector nodeConnector, UpdateType updateType, Set<org.opendaylight.controller.sal.core.Property> properties){
+        for( publisher : inventoryPublisher){
+            publisher.updateNodeConnector(nodeConnector, updateType, properties);
+        }
+    }
+
+    private def isKnownNodeConnector(InstanceIdentifier<? extends Object> nodeConnectorIdentifier){
+        if(nodeConnectorIdentifier.path.size() < 3) {
+            return false;
+        }
 
+        val nodePath = nodeConnectorIdentifier.path.get(1);
+        val nodeConnectorPath = nodeConnectorIdentifier.getPath().get(2);
 
-       private def publishNodeUpdate(Node node, UpdateType updateType, Set<org.opendaylight.controller.sal.core.Property> properties){
-           for( publisher : inventoryPublisher){
-               publisher.updateNode(node, updateType, properties);
-           }
-       }
+        val nodeConnectors = nodeToNodeConnectorsMap.get(nodePath);
 
-       private def publishNodeConnectorUpdate(org.opendaylight.controller.sal.core.NodeConnector nodeConnector, UpdateType updateType, Set<org.opendaylight.controller.sal.core.Property> properties){
-           for( publisher : inventoryPublisher){
-               publisher.updateNodeConnector(nodeConnector, updateType, properties);
-           }
-       }
+        if(nodeConnectors == null){
+            return false;
+        }
+        return nodeConnectors.contains(nodeConnectorPath);
+    }
+
+
+    private def recordNodeConnector(InstanceIdentifier<? extends Object> nodeConnectorIdentifier){
+        if(nodeConnectorIdentifier.path.size() < 3) {
+            return false;
+        }
+
+        val nodePath = nodeConnectorIdentifier.path.get(1);
+        val nodeConnectorPath = nodeConnectorIdentifier.getPath().get(2);
+
+        nodeToNodeConnectorsLock.lock();
+
+        try {
+            var nodeConnectors = nodeToNodeConnectorsMap.get(nodePath);
+
+            if(nodeConnectors == null){
+                nodeConnectors = new ArrayList<InstanceIdentifier.PathArgument>();
+                nodeToNodeConnectorsMap.put(nodePath, nodeConnectors);
+            }
+
+            nodeConnectors.add(nodeConnectorPath);
+        } finally {
+            nodeToNodeConnectorsLock.unlock();
+        }
+    }
+
+    private def removeNodeConnectors(InstanceIdentifier<? extends Object> nodeIdentifier){
+        val nodePath = nodeIdentifier.path.get(1);
+
+        nodeToNodeConnectorsMap.remove(nodePath);
+    }
 }
diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryNotificationProvider.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryNotificationProvider.java
new file mode 100644 (file)
index 0000000..23a98ff
--- /dev/null
@@ -0,0 +1,59 @@
+package org.opendaylight.controller.sal.compatibility;
+
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+public class InventoryNotificationProvider implements AutoCloseable{
+
+    private ListenerRegistration<DataChangeListener> nodeConnectorDataChangeListenerRegistration;
+
+    private NodeConnectorDataChangeListener nodeConnectorDataChangeListener;
+
+    private DataProviderService dataProviderService;
+
+    private List<IPluginOutInventoryService> inventoryPublisher;
+
+    private final static Logger LOG = LoggerFactory.getLogger(NodeConnectorDataChangeListener.class);
+
+    public void start(){
+
+        LOG.info("InventoryNotificationProvider started");
+
+        if(dataProviderService != null
+                && inventoryPublisher!= null){
+
+            if(nodeConnectorDataChangeListener == null){
+                InstanceIdentifier nodeConnectorPath = InstanceIdentifier.builder(Nodes.class).child(Node.class).child(NodeConnector.class).build();
+                nodeConnectorDataChangeListener = new NodeConnectorDataChangeListener();
+                nodeConnectorDataChangeListener.setInventoryPublisher(inventoryPublisher);
+                nodeConnectorDataChangeListenerRegistration = dataProviderService.registerDataChangeListener(nodeConnectorPath, nodeConnectorDataChangeListener);
+            }
+
+        }
+    }
+
+    @Override
+    public void close() throws Exception {
+        if(nodeConnectorDataChangeListenerRegistration != null){
+            nodeConnectorDataChangeListenerRegistration.close();
+        }
+    }
+
+    public void setDataProviderService(DataProviderService dataProviderService) {
+        this.dataProviderService = dataProviderService;
+    }
+
+    public void setInventoryPublisher(List<IPluginOutInventoryService> inventoryPublisher) {
+        this.inventoryPublisher = inventoryPublisher;
+    }
+}
diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeConnectorDataChangeListener.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeConnectorDataChangeListener.java
new file mode 100644 (file)
index 0000000..eebba74
--- /dev/null
@@ -0,0 +1,77 @@
+package org.opendaylight.controller.sal.compatibility;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.core.ConstructionException;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.Property;
+import org.opendaylight.controller.sal.core.UpdateType;
+import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+// org.opendaylight.controller.sal.compatibility.NodeConnectorDataChangeListener
+public class NodeConnectorDataChangeListener implements DataChangeListener{
+    private final static Logger LOG = LoggerFactory.getLogger(NodeConnectorDataChangeListener.class);
+
+    private List<IPluginOutInventoryService> inventoryPublisher;
+
+    public List<IPluginOutInventoryService> getInventoryPublisher() {
+      return this.inventoryPublisher;
+    }
+
+    public void setInventoryPublisher(final List<IPluginOutInventoryService> inventoryPublisher) {
+      this.inventoryPublisher = inventoryPublisher;
+    }
+
+    @Override
+    public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+        final Map<InstanceIdentifier<?>,DataObject> createdOperationalData = change.getCreatedOperationalData();
+        final Map<InstanceIdentifier<?>,DataObject> updatedOperationalData = change.getUpdatedOperationalData();
+
+        final Set<Map.Entry<InstanceIdentifier<?>,DataObject>> createdEntries = createdOperationalData.entrySet();
+        final Set<Map.Entry<InstanceIdentifier<?>,DataObject>> updatedEntries = new HashSet<>();
+
+        updatedEntries.addAll(updatedOperationalData.entrySet());
+        updatedEntries.removeAll(createdEntries);
+
+        for(final Map.Entry<InstanceIdentifier<?>,DataObject> entry : createdEntries){
+            publishNodeConnectorUpdate(entry, UpdateType.ADDED);
+        }
+
+        for(final Map.Entry<InstanceIdentifier<?>,DataObject> entry : updatedEntries){
+            publishNodeConnectorUpdate(entry, UpdateType.CHANGED);
+        }
+    }
+
+    private void publishNodeConnectorUpdate(final Map.Entry<InstanceIdentifier<?>,DataObject> entry, final UpdateType updateType) {
+        if (entry.getKey().getTargetType().equals(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector.class)) {
+            NodeConnectorRef nodeConnectorRef = new NodeConnectorRef(entry.getKey());
+            NodeConnector nodeConnector = null;
+            try {
+                nodeConnector = NodeMapping.toADNodeConnector(nodeConnectorRef);
+            } catch (ConstructionException e) {
+                e.printStackTrace();
+            }
+            HashSet<Property> _aDNodeConnectorProperties = NodeMapping.toADNodeConnectorProperties((org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector) entry.getValue());
+            this.publishNodeConnectorUpdate(nodeConnector, updateType, _aDNodeConnectorProperties);
+        }
+    }
+
+    private void publishNodeConnectorUpdate(final NodeConnector nodeConnector, final UpdateType updateType, final Set<Property> properties) {
+      LOG.debug("Publishing NodeConnector " + updateType.toString() + " nodeConnector Id = " + nodeConnector.getNodeConnectorIdAsString());
+
+      List<IPluginOutInventoryService> _inventoryPublisher = getInventoryPublisher();
+      for (final IPluginOutInventoryService publisher : _inventoryPublisher) {
+        publisher.updateNodeConnector(nodeConnector, updateType, properties);
+      }
+    }
+}
index 40de6e550742f727af5a84450c84fb8ec5bbd7d6..84508ca03e99475b7a95fcc0a0e676082e227f04 100644 (file)
@@ -14,9 +14,7 @@ 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.NodeMapping;
 import org.opendaylight.controller.sal.compatibility.ToSalConversionsUtils;
-import org.opendaylight.controller.sal.core.ConstructionException;
 import org.opendaylight.controller.sal.flowprogrammer.Flow;
 import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerListener;
 import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerService;
index 1a66b3ba16316b4c5a1c92485e909cf061c3d398..43f48a50e56175a2297e78e32478f80404ff839d 100644 (file)
@@ -64,6 +64,8 @@ class FlowCapableInventoryProvider implements AutoCloseable {
 
 class NodeChangeCommiter implements OpendaylightInventoryListener {
 
+    static val LOG = LoggerFactory.getLogger(NodeChangeCommiter);
+
     @Property
     val FlowCapableInventoryProvider manager;
 
@@ -76,6 +78,9 @@ class NodeChangeCommiter implements OpendaylightInventoryListener {
 
         // Check path
         val it = manager.startChange()
+
+        LOG.debug("removing node connector : " + ref.value.toString());
+
         removeOperationalData(ref.value as InstanceIdentifier<? extends DataObject>);
         commit()
     }
@@ -93,6 +98,8 @@ class NodeChangeCommiter implements OpendaylightInventoryListener {
             data.addAugmentation(FlowCapableNodeConnector, augment)
         }
 
+        LOG.debug("updating node connector : " + ref.value.toString());
+
         putOperationalData(ref.value as InstanceIdentifier<NodeConnector>, data.build());
         commit()
     }
@@ -101,6 +108,8 @@ class NodeChangeCommiter implements OpendaylightInventoryListener {
         val ref = node.nodeRef;
         val it = manager.startChange()
 
+        LOG.debug("removing node : " + ref.value.toString());
+
         removeOperationalData(ref.value as InstanceIdentifier<? extends DataObject>);
         commit()
     }
@@ -117,6 +126,8 @@ class NodeChangeCommiter implements OpendaylightInventoryListener {
             data.addAugmentation(FlowCapableNode, augment)
         }
 
+        LOG.debug("updating node : " + ref.value.toString());
+
         putOperationalData(ref.value as InstanceIdentifier<Node>, data.build())
         commit()
     }
index a7c74c573b04e229cb9444b405e7ebdbd6da5a3d..d7d678d89a599d54c531856c3d601410ce5b1792 100644 (file)
@@ -19,7 +19,6 @@
         <dependency>
             <groupId>org.opendaylight.yangtools.model</groupId>
             <artifactId>opendaylight-l2-types</artifactId>
-            <version>2013.08.27.3</version>
         </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
index 321e0540974e3ccc5838e1638e251d6e47fd4b26..b02b0dc25cbf3ade673b927d0851ee898f69432c 100644 (file)
@@ -8,7 +8,7 @@ module opendaylight-match-types {
     import opendaylight-inventory {prefix inv;revision-date "2013-08-19";}
 
     revision "2013-10-26" {
-        description "Initial revision of macth types";
+        description "Initial revision of match types";
     }
 
     grouping "mac-address-filter" {
index 118db1af06fdbd809ec1f21217bbfe1a84c27cbe..e74b5483428fc1765e8bf29b763fb840c688fd25 100644 (file)
@@ -191,6 +191,7 @@ module opendaylight-table-types {
         
     grouping set-field-match {
         list set-field-match {
+           key "match-type";
             leaf match-type {
                 type identityref {
                     base match-field;
index 55837564c304bbadf8559b314ee293891aceb4f8..5604ea98cff2aedc9c8ca212a2ee73840f528e82 100644 (file)
@@ -29,7 +29,6 @@
         <dependency>
             <groupId>org.opendaylight.yangtools.model</groupId>
             <artifactId>opendaylight-l2-types</artifactId>
-            <version>2013.08.27.3</version>
         </dependency>
     </dependencies>
     <packaging>bundle</packaging>
index 091bd43e1973ac8f2ec6aaea93717fe386e25af4..b3e6e450af8c3f9d4b0d593b91547e0f48023620 100644 (file)
@@ -4,7 +4,9 @@ module sal-flow {
 
     import yang-ext {prefix ext; revision-date "2013-07-09";}
     import opendaylight-inventory {prefix inv;revision-date "2013-08-19";}
-    import opendaylight-flow-types {prefix types;revision-date "2013-10-26";}
+    import opendaylight-flow-types {prefix types;revision-date "2013-10-26";}    
+    import opendaylight-group-types {prefix group-type;revision-date 2013-10-18;}
+    import opendaylight-meter-types {prefix meter-type;revision-date "2013-09-18";}
     import flow-capable-transaction {prefix tr;}
     import flow-errors {prefix error;}
 
@@ -122,6 +124,28 @@ module sal-flow {
         uses error:error-message;
         uses tr:transaction-aware;
         uses tr:transaction-metadata;
+        choice object-reference {
+        case flow-ref{
+                   leaf flow-ref {
+            type types:flow-ref;
+         }
+       }
+        case group-ref{
+                   leaf group-ref {
+            type group-type:group-ref;
+         }
+       }
+        case meter-ref{
+                   leaf meter-ref {
+            type meter-type:meter-ref;
+         }
+       }
+     }
+        leaf node {
+            ext:context-reference "inv:node-context";
+            type inv:node-ref;
+        }
+        
     }
     
     notification node-experimenter-error-notification {
index 2f594148c98290f96e8b2d2288da2d4166bec177..f900c0b18c6558e0808c7fca3452bf3608aaeddf 100644 (file)
 
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-        <nexusproxy>http://nexus.opendaylight.org/content</nexusproxy>
-        <!-- Java Versions -->
-        <maven.compiler.source>1.7</maven.compiler.source>
-        <maven.compiler.target>1.7</maven.compiler.target>
 
         <!-- Plugin Versions -->
         <bundle.plugin.version>2.4.0</bundle.plugin.version>
-        <releaseplugin.version>2.3.2</releaseplugin.version>
+        <maven.clean.plugin.version>2.5</maven.clean.plugin.version>
 
         <!-- Dependency Versions -->
-        <slf4j.version>1.7.2</slf4j.version>
-        <guava.version>14.0.1</guava.version>
-        <osgi.core.version>5.0.0</osgi.core.version>
-        <junit.version>4.8.1</junit.version>
         <mockito.version>1.9.5</mockito.version>
         <xtend.version>2.4.3</xtend.version>
-        <maven.clean.plugin.version>2.5</maven.clean.plugin.version>
-        <jacoco.version>0.5.3.201107060350</jacoco.version>
 
         <!-- Sonar properties using jacoco to retrieve integration test results -->
         <sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
         <sal.version>0.7.1-SNAPSHOT</sal.version>
     </properties>
 
-    <pluginRepositories>
-        <!-- OpenDayLight Repo Mirror -->
-        <pluginRepository>
-            <id>opendaylight-mirror</id>
-            <name>opendaylight-mirror</name>
-            <url>${nexusproxy}/groups/public/</url>
-            <snapshots>
-                <enabled>false</enabled>
-            </snapshots>
-            <releases>
-                <enabled>true</enabled>
-                <updatePolicy>never</updatePolicy>
-            </releases>
-        </pluginRepository>
-        <!-- OpenDayLight Snapshot artifact -->
-        <pluginRepository>
-            <id>opendaylight-snapshot</id>
-            <name>opendaylight-snapshot</name>
-            <url> ${nexusproxy}/repositories/opendaylight.snapshot/</url>
-            <snapshots>
-                <enabled>true</enabled>
-            </snapshots>
-            <releases>
-                <enabled>false</enabled>
-            </releases>
-        </pluginRepository>
-    </pluginRepositories>
-
-
-    <repositories>
-        <!-- OpenDayLight Repo Mirror -->
-        <repository>
-            <id>opendaylight-mirror</id>
-            <name>opendaylight-mirror</name>
-            <url>${nexusproxy}/groups/public/</url>
-            <snapshots>
-                <enabled>false</enabled>
-            </snapshots>
-            <releases>
-                <enabled>true</enabled>
-                <updatePolicy>never</updatePolicy>
-            </releases>
-        </repository>
-        <!-- OpenDayLight Snapshot artifact -->
-        <repository>
-            <id>opendaylight-snapshot</id>
-            <name>opendaylight-snapshot</name>
-            <url> ${nexusproxy}/repositories/opendaylight.snapshot/</url>
-            <snapshots>
-                <enabled>true</enabled>
-            </snapshots>
-            <releases>
-                <enabled>false</enabled>
-            </releases>
-        </repository>
-    </repositories>
-
-    <distributionManagement>
-        <!-- OpenDayLight Released artifact -->
-        <repository>
-            <id>opendaylight-release</id>
-            <url>${nexusproxy}/repositories/opendaylight.release/</url>
-        </repository>
-        <!-- OpenDayLight Snapshot artifact -->
-        <snapshotRepository>
-            <id>opendaylight-snapshot</id>
-            <url>${nexusproxy}/repositories/opendaylight.snapshot/</url>
-        </snapshotRepository>
-        <!-- Site deployment -->
-        <site>
-            <id>website</id>
-            <url>${sitedeploy}</url>
-        </site>
-    </distributionManagement>
-
-
     <dependencyManagement>
         <dependencies>
             <dependency>
                 <version>1.4.01</version>
             </dependency>
 
-            <!-- YANG Tools Dependencies -->
-            <dependency>
-                <groupId>org.opendaylight.yangtools</groupId>
-                <artifactId>yang-binding</artifactId>
-                <version>${yangtools.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.opendaylight.yangtools</groupId>
-                <artifactId>yang-model-util</artifactId>
-                <version>${yangtools.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.opendaylight.yangtools</groupId>
-                <artifactId>yang-common</artifactId>
-                <version>${yangtools.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.opendaylight.yangtools</groupId>
-                <artifactId>yang-data-api</artifactId>
-                <version>${yangtools.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.opendaylight.yangtools</groupId>
-                <artifactId>yang-data-impl</artifactId>
-                <version>${yangtools.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.opendaylight.yangtools</groupId>
-                <artifactId>yang-model-api</artifactId>
-                <version>${yangtools.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.opendaylight.yangtools</groupId>
-                <artifactId>yang-data-util</artifactId>
-                <version>${yangtools.version}</version>
-            </dependency>
             <!-- SAL Dependencies -->
             <dependency>
                 <groupId>${project.groupId}</groupId>
                 <artifactId>sal-connector-api</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.opendaylight.controller</groupId>
+                <artifactId>sal-binding-api</artifactId>
+                <version>${project.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.opendaylight.controller</groupId>
                 <artifactId>sal</artifactId>
                     </exclusion>
                 </exclusions>
             </dependency>
+            <dependency>
+                <groupId>org.opendaylight.controller</groupId>
+                <artifactId>sal-remote</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.opendaylight.controller</groupId>
+                <artifactId>sal-binding-util</artifactId>
+                <version>${project.version}</version>
+            </dependency>
 
             <!-- Supporting Libraries -->
             <dependency>
                 <artifactId>slf4j-api</artifactId>
                 <version>${slf4j.version}</version>
             </dependency>
-            <dependency>
-                <groupId>com.google.guava</groupId>
-                <artifactId>guava</artifactId>
-                <version>${guava.version}</version>
-            </dependency>
             <dependency>
                 <groupId>org.eclipse.xtend</groupId>
                 <artifactId>org.eclipse.xtend.lib</artifactId>
                 <artifactId>org.osgi.core</artifactId>
                 <version>${osgi.core.version}</version>
             </dependency>
-            <!-- Testing Dependencies -->
-            <dependency>
-                <groupId>junit</groupId>
-                <artifactId>junit</artifactId>
-                <version>${junit.version}</version>
-                <scope>test</scope>
-            </dependency>
-            <dependency>
-                <groupId>org.mockito</groupId>
-                <artifactId>mockito-all</artifactId>
-                <version>${mockito.version}</version>
-                <scope>test</scope>
-            </dependency>
             <dependency>
                 <groupId>org.opendaylight.yangtools</groupId>
                 <artifactId>binding-generator-impl</artifactId>
                 <artifactId>yang-parser-impl</artifactId>
                <version>${yangtools.version}</version>
             </dependency>
+
+            <!-- Testing Dependencies -->
+            <dependency>
+                <groupId>org.mockito</groupId>
+                <artifactId>mockito-all</artifactId>
+                <version>${mockito.version}</version>
+                <scope>test</scope>
+            </dependency>
         </dependencies>
     </dependencyManagement>
     <build>
         <pluginManagement>
             <plugins>
-                <plugin>
-                    <groupId>org.apache.maven.plugins</groupId>
-                    <artifactId>maven-release-plugin</artifactId>
-                    <version>${releaseplugin.version}</version>
-                </plugin>
                 <plugin>
                     <groupId>org.apache.felix</groupId>
                     <artifactId>maven-bundle-plugin</artifactId>
index fc145c8b16e0d9dff7e0c29e480ff5fe9935f4dd..02bb6b35b9165e29aa22f077488c1969354a2175 100644 (file)
@@ -7,10 +7,7 @@
  */
 package org.opendaylight.controller.sal.binding.api;
 
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
-import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
 
 public abstract class AbstractBindingAwareConsumer extends AbstractBrokerAwareActivator implements BindingAwareConsumer {
 
index 9d3bff4ef8b9d4d954f3f10b31d3789d655ad59e..068b6c204f3d75db69a57dcd0db873548d158343 100644 (file)
@@ -13,12 +13,10 @@ import java.util.Collections;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
 import org.opendaylight.yangtools.yang.binding.RpcService;
-import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
 
 public abstract class AbstractBindingAwareProvider extends AbstractBrokerAwareActivator implements BindingAwareProvider {
-    
+
     @Override
     protected final void onBrokerAvailable(BindingAwareBroker broker, BundleContext context) {
         ProviderContext ctx = broker.registerProvider(this, context);
@@ -57,13 +55,13 @@ public abstract class AbstractBindingAwareProvider extends AbstractBrokerAwareAc
     public Collection<? extends RpcService> getImplementations() {
         return Collections.emptySet();
     }
-    
+
     /**
      * Initialization of consumer context.
-     * 
+     *
      * {@link ProviderContext} is replacement of {@link ConsumerContext}
      * so this method is not needed in case of Provider.
-     * 
+     *
      */
     @Deprecated
     @Override
index c28b03eb65a092817917956cc9794a8267c41479..08029dc52fa2c35fe1ea0f4b7994ef6eecf3fbe2 100644 (file)
@@ -12,7 +12,6 @@ import java.util.concurrent.ExecutorService;
 
 import org.opendaylight.controller.md.sal.common.api.notify.NotificationPublishService;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
-import org.opendaylight.yangtools.concepts.Registration;
 import org.opendaylight.yangtools.yang.binding.Notification;
 
 public interface NotificationProviderService extends NotificationService, NotificationPublishService<Notification> {
@@ -20,7 +19,7 @@ public interface NotificationProviderService extends NotificationService, Notifi
 
     /**
      * Deprecated. Use {@link #publish(Notification)}.
-     * 
+     *
      * @param notification
      */
     @Deprecated
@@ -28,7 +27,7 @@ public interface NotificationProviderService extends NotificationService, Notifi
 
     /**
      * Deprecated. Use {@link #publish(Notification,ExecutorService)}.
-     * 
+     *
      * @param notification
      */
     @Deprecated
@@ -36,17 +35,17 @@ public interface NotificationProviderService extends NotificationService, Notifi
 
     /**
      * Publishes a notification.
-     * 
+     *
      * @param Notification
      *            notification to publish.
-     * 
+     *
      */
     @Override
     void publish(Notification notification);
 
     /**
      * Publishes a notification, listener calls are done in provided executor.
-     * 
+     *
      */
     @Override
     void publish(Notification notification, ExecutorService service);
index 10b29f721873bd2bd78573b071f3e771e5549d3c..24ca2a3de7e13073b0e61e2be930ebabf04d9436 100644 (file)
@@ -7,25 +7,23 @@
  */
 package org.opendaylight.controller.sal.binding.api;
 
-import org.opendaylight.controller.md.sal.common.api.notify.NotificationSubscriptionService;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.concepts.Registration;
 import org.opendaylight.yangtools.yang.binding.Notification;
 
 public interface NotificationService extends BindingAwareService {
     /**
-     * 
+     *
      * Deprecated: use {@link #addNotificationListener(Class, NotificationListener)} istead.
-     * 
+     *
      * @param listener
      */
     @Deprecated
     <T extends Notification> void addNotificationListener(Class<T> notificationType, NotificationListener<T> listener);
 
     /**
-     * 
+     *
      * Deprecated: use {@link #addNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener)} istead.
-     * 
+     *
      * @param listener
      */
     @Deprecated
@@ -45,10 +43,10 @@ public interface NotificationService extends BindingAwareService {
     @Deprecated
     <T extends Notification> void removeNotificationListener(Class<T> notificationType, NotificationListener<T> listener);
 
-    
+
     /**
      * Register a generic listener for specified notification type only.
-     * 
+     *
      * @param notificationType
      * @param listener
      * @return Registration for listener. To unregister listener invoke {@link Registration#close()} method.
@@ -61,7 +59,7 @@ public interface NotificationService extends BindingAwareService {
      * Register a listener which implements generated notification interfaces derived from
      * {@link org.opendaylight.yangtools.yang.binding.NotificationListener}.
      * Listener is registered for all notifications present in implemented interfaces.
-     * 
+     *
      * @param listener
      * @return Registration for listener. To unregister listener invoke {@link Registration#close()} method.
      */
index 33b384a94c652d0ffe196e3319393413407e5cad..69a2108065b7710a658a496486eac9c1f22bc9f7 100644 (file)
@@ -19,8 +19,6 @@ public interface RpcConsumerRegistry extends BindingAwareService {
      * Returns a session specific instance (implementation) of requested
      * YANG module implentation / service provided by consumer.
      * 
-     * @param service
-     *            Broker service
      * @return Session specific implementation of service
      */
     <T extends RpcService> T getRpcService(Class<T> module);
index fcf8ed5c9e65e40ce4bdb79eb9d96e440fcf1c21..c64e24c9c232d2aab54847713c7f5f1c7aa236dd 100644 (file)
@@ -11,23 +11,22 @@ import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublishe
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
 import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.RpcService;
 
 /**
  * Interface defining provider's access to the Rpc Registry which could be used
  * to register their implementations of service to the MD-SAL.
- * 
+ *
  * @author ttkacik
- * 
+ *
  */
 public interface RpcProviderRegistry extends //
         RpcConsumerRegistry, //
         RouteChangePublisher<RpcContextIdentifier, InstanceIdentifier<?>> {
     /**
      * Registers an global RpcService implementation.
-     * 
+     *
      * @param type
      * @param implementation
      * @return
@@ -36,10 +35,10 @@ public interface RpcProviderRegistry extends //
             throws IllegalStateException;
 
     /**
-     * 
+     *
      * Register an Routed RpcService where routing is determined on annotated
      * (in YANG model) context-reference and value of annotated leaf.
-     * 
+     *
      * @param type
      *            Type of RpcService, use generated interface class, not your
      *            implementation clas
@@ -47,7 +46,7 @@ public interface RpcProviderRegistry extends //
      *            Implementation of RpcService
      * @return Registration object for routed Rpc which could be used to close
      *         an
-     * 
+     *
      * @throws IllegalStateException
      */
     <T extends RpcService> RoutedRpcRegistration<T> addRoutedRpcImplementation(Class<T> type, T implementation)
index 9ce11c71e4b6d1a41fa61a4dfa94401700db97e1..719063832314cfa069121fb92d79c62165439424 100644 (file)
@@ -11,9 +11,9 @@ import java.util.EventListener;
 import java.util.concurrent.Future;
 
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
 import org.opendaylight.controller.md.sal.common.api.data.DataModification;
 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.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
@@ -22,28 +22,28 @@ public interface DataModificationTransaction extends DataModification<InstanceId
 
     /**
      * Returns an unique identifier for transaction
-     * 
+     *
      */
     @Override
     public Object getIdentifier();
-    
+
     /**
      * 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
@@ -53,12 +53,12 @@ public interface DataModificationTransaction extends DataModification<InstanceId
      */
     @Override
     public Future<RpcResult<TransactionStatus>> commit();
-    
-    
-    
+
+
+
     /**
      * Register a listener for transaction
-     * 
+     *
      * @param listener
      * @return
      */
@@ -68,13 +68,13 @@ public interface DataModificationTransaction extends DataModification<InstanceId
 
     /**
      * Listener for transaction state changes
-     * 
+     *
      *
      */
     public interface DataTransactionListener extends EventListener {
         /**
          * Callback is invoked after each transaction status change.
-         * 
+         *
          * @param transaction Transaction
          * @param status New status
          */
index 523abb50cab4150421c46d61d6aa345ccab98cd5..7d662cfcf20ebc60bd722fded3a6b04ab6eda9c7 100644 (file)
@@ -11,7 +11,6 @@ package org.opendaylight.controller.sal.binding.api.data;
 import org.opendaylight.controller.md.sal.common.api.data.DataProvisionService;
 import org.opendaylight.controller.md.sal.common.api.data.DataReader;
 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;
 import org.opendaylight.yangtools.concepts.Registration;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -23,15 +22,15 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
  */
 public interface DataProviderService extends DataBrokerService, DataProvisionService<InstanceIdentifier<? extends DataObject>, DataObject> {
 
-    
+
     /**
      * Registers a data reader for particular subtree of overal YANG data tree.
-     * 
-     * Registered data reader is called if anyone tries to read data from 
+     *
+     * Registered data reader is called if anyone tries to read data from
      * paths which are nested to provided path.
-     * 
+     *
      * @param path Subpath which is handled by registered data reader
-     * @param reader Instance of reader which 
+     * @param reader Instance of reader which
      * @return Registration object for reader. Invoking {@link Registration#close()} will unregister reader.
      */
     Registration<DataReader<InstanceIdentifier<? extends DataObject>,DataObject>> registerDataReader(InstanceIdentifier<? extends DataObject> path,DataReader<InstanceIdentifier<? extends DataObject>,DataObject> reader);
index f54e1315be06a546ad6d62c4a92a693c8b3197cd..3334f2a037b119711916a52ad7c9d86b6424201d 100644 (file)
@@ -8,19 +8,18 @@
 package org.opendaylight.controller.sal.binding.api.data;
 
 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
-import org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality;
 
 /**
  * Trigger for refreshing of the data exposed by the {@link Provider}
- * 
- * 
- * 
+ *
+ *
+ *
  */
 public interface DataRefresher extends BindingAwareProvider.ProviderFunctionality {
 
     /**
      * Fired when some component explicitly requested the data refresh.
-     * 
+     *
      * The provider which exposed the {@link DataRefresher} should republish its
      * provided data by editing the data in all affected data stores.
      */
index 652e14bfa5b6683797ff9b0d3e339373e8bcdb61..85a2b82ee0397174966e8e584a6607eb61de3433 100644 (file)
@@ -7,23 +7,19 @@
  */
 package org.opendaylight.controller.sal.binding.api.data;
 
-import java.util.Set;
-
 import org.opendaylight.controller.md.sal.common.api.data.DataReader;
 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality;
-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;
 
 /**
- * Utility interface which does type capture for BindingAware DataReader. 
- * 
- * @author 
+ * Utility interface which does type capture for BindingAware DataReader.
+ *
+ * @author
  *
  */
 public interface RuntimeDataProvider extends ProviderFunctionality,DataReader<InstanceIdentifier<? extends DataObject>, DataObject> {
-    
-    
+
+
 
 }
index 844b03a18050de2a80f494675f8624214ec722f0..b4441601cb5c23c52b3e4b63f56af73a40394a03 100644 (file)
@@ -12,7 +12,6 @@ import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry;
 import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
 import org.opendaylight.yangtools.concepts.Identifiable;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.RpcService;
 
 public interface MountInstance //
         extends //
index f7b584507a85f500d1d603b59736ab48ea37a73f..6af9093fdd4c79c101808e528c8546b26a8b3056 100644 (file)
@@ -9,21 +9,19 @@ package org.opendaylight.controller.sal.binding.api.mount;
 
 import java.util.EventListener;
 
-import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
-import org.opendaylight.yangtools.concepts.Registration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
 /**
  * Provider MountProviderService, this version allows access to MD-SAL services
  * specific for this mountpoint and registration / provision of interfaces for
  * mount point.
- * 
+ *
  * @author ttkacik
- * 
+ *
  */
 public interface MountProviderService extends MountService {
-    
+
     @Override
     public MountProviderInstance getMountPoint(InstanceIdentifier<?> path);
 
index 31fed62d876ef5b8e25512023393204bf1856d02..81fe39c62e0c927cbe43110fabe76af640b71874 100644 (file)
@@ -14,17 +14,16 @@ import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcR
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
 import org.opendaylight.yangtools.yang.binding.BaseIdentity;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.RpcImplementation;
 import org.opendaylight.yangtools.yang.binding.RpcService;
 
 /**
  * RpcRouter is responsible for selecting RpcService based on provided routing
  * context identifier {@link RpcRoutingTable#getContextIdentifier()} and path in
  * overal data tree (@link {@link InstanceIdentifier}.
- * 
- * 
+ *
+ *
  * @author Tony Tkacik <ttkacik@cisco.com>
- * 
+ *
  * @param <T>
  *            Type of RpcService for which router provides routing information
  *            and route selection.
@@ -34,23 +33,23 @@ public interface RpcRouter<T extends RpcService> extends //
 
     /**
      * Returns a type of RpcService which is served by this instance of router.
-     * 
+     *
      * @return type of RpcService which is served by this instance of router.
      */
     Class<T> getServiceType();
-    
-    
+
+
     /**
      * Returns a instance of T which is associated with this router instance
      * and routes messages based on routing tables.
-     * 
+     *
      * @return type of RpcService which is served by this instance of router.
      */
     T getInvocationProxy();
 
     /**
      * Returns a routing table for particular route context
-     * 
+     *
      * @param routeContext
      * @return Routing Table for particular route context.
      */
@@ -59,7 +58,7 @@ public interface RpcRouter<T extends RpcService> extends //
     /**
      * Returns an instance of RpcService which is responsible for processing
      * particular path.
-     * 
+     *
      * @param context
      *            Rpc Routing Context
      * @param path
@@ -72,15 +71,15 @@ public interface RpcRouter<T extends RpcService> extends //
     /**
      * Returns a default fallback instance of RpcService which is responsible
      * for handling all unknown imports.
-     * 
+     *
      * @return default instance responsible for processing RPCs.
      */
     T getDefaultService();
 
     Set<Class<? extends BaseIdentity>> getContexts();
-    
+
     RoutedRpcRegistration<T> addRoutedRpcImplementation(T service);
-    
+
     RpcRegistration<T> registerDefaultService(T service);
 
 }
index e5a74e42a155fee7a587890fc91b0b9d3e4a9b12..fd2c8a2fa4b8026c94b7981e91ea3216a911fa5e 100644 (file)
                             org.opendaylight.controller.sal.binding.impl.*,
                             org.opendaylight.controller.sal.binding.codegen,
                             org.opendaylight.controller.sal.binding.codegen.*,
-                            org.opendaylight.controller.sal.binding.dom.*,
+                            <!--org.opendaylight.controller.sal.binding.dom.*,-->
                             org.opendaylight.controller.sal.binding.osgi.*,
                         </Private-Package>
                     </instructions>
index ffc83792284cbd0dc044cef26dfc5d0b43e99fe5..44a508c0a0bd2561c20517323f47735479688611 100644 (file)
@@ -23,8 +23,6 @@ import org.opendaylight.controller.sal.binding.impl.forward.DomForwardedBindingB
 import org.opendaylight.controller.sal.binding.impl.forward.DomForwardingUtils;\r
 import org.osgi.framework.BundleContext;\r
 \r
-import com.google.common.util.concurrent.MoreExecutors;\r
-\r
 /**\r
 *\r
 */\r
index 286b0c378ca7183589e3001105db2be973e8222a..7357926b9e6226a612bd0fc453dc28b737cff5b8 100644 (file)
@@ -7,17 +7,17 @@
  */
 package org.opendaylight.controller.config.yang.md.sal.binding.impl;\r
 \r
-import java.util.concurrent.ExecutorService;\r
-\r
-import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder;\r
-import org.opendaylight.controller.sal.binding.impl.RootDataBrokerImpl;\r
-import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingDomConnectorDeployer;\r
-import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector;\r
-import org.opendaylight.controller.sal.binding.impl.forward.DomForwardedDataBrokerImpl;\r
-import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;\r
-import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;\r
-import org.osgi.framework.BundleContext;\r
-import org.osgi.framework.ServiceReference;\r
+import java.util.concurrent.ExecutorService;
+
+import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder;
+import org.opendaylight.controller.sal.binding.impl.RootDataBrokerImpl;
+import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingDomConnectorDeployer;
+import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector;
+import org.opendaylight.controller.sal.binding.impl.forward.DomForwardedDataBrokerImpl;
+import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
 \r
 /**\r
 *\r
@@ -57,14 +57,14 @@ public final class DataBrokerImplModule extends
             dataBindingBroker = createStandAloneBroker(listeningExecutor);\r
         }\r
         dataBindingBroker.registerRuntimeBean(getRootRuntimeBeanRegistratorWrapper());\r
-\r
+        dataBindingBroker.setNotificationExecutor(SingletonHolder.getDefaultChangeEventExecutor());\r
         return dataBindingBroker;\r
     }\r
     private BindingIndependentMappingService resolveMappingServiceDependency() {\r
         if(getMappingService() != null) {\r
             return getMappingServiceDependency();\r
         }\r
-        \r
+\r
         ServiceReference<BindingIndependentMappingService> potentialMappingService = bundleContext.getServiceReference(BindingIndependentMappingService.class);\r
         if(potentialMappingService != null) {\r
             return bundleContext.getService(potentialMappingService);\r
index 0a503d56428352ee7a4da76be4ae738e44fddc7f..b6c27a6332c4fdc7ddc6c08e25970f51431c8260 100644 (file)
@@ -7,15 +7,10 @@
  */
 package org.opendaylight.controller.config.yang.md.sal.binding.impl;
 
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-
 import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder;
 import org.opendaylight.controller.sal.binding.impl.NotificationBrokerImpl;
 
 import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.common.util.concurrent.MoreExecutors;
 
 /**
 *
index a2b3d17b7c044602c99c966b3b2b1b1f2dcc5ed9..14006a3fce2ff3eea04e4fcae84bf0e412ea850b 100644 (file)
@@ -7,12 +7,11 @@
  */
 package org.opendaylight.controller.config.yang.md.sal.binding.impl;
 
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
 import java.util.Hashtable;
 import java.util.Map.Entry;
 import java.util.Set;
-
-import javassist.ClassPool;
-
 import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder;
 import org.opendaylight.yangtools.concepts.Delegator;
 import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl;
@@ -29,8 +28,6 @@ import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 
-import com.google.common.base.Preconditions;
-
 /**
 *
 */
@@ -147,6 +144,11 @@ public final class RuntimeMappingModule extends
             return delegate.getRpcQNamesFor(service);
         }
 
+        @Override
+        public Optional<Class<? extends RpcService>> getRpcServiceClassFor(String namespace, String revision) {
+            return delegate.getRpcServiceClassFor(namespace,revision);
+        }
+
         public DataContainer dataObjectFromDataDom(Class<? extends DataContainer> inputClass, CompositeNode domInput) {
             return delegate.dataObjectFromDataDom(inputClass, domInput);
         }
index 4f994e5673a2c80896d8c5168af4d0c299ee7bcf..5578f75ae21d6800cf2c73661afa15a071bd6ef8 100644 (file)
@@ -7,29 +7,26 @@
  */
 package org.opendaylight.controller.sal.binding.codegen.impl;
 
-import org.opendaylight.yangtools.yang.binding.RpcService;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
-import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter;
-import org.opendaylight.controller.sal.binding.api.rpc.RpcRoutingTable;
-import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper;
-import org.opendaylight.yangtools.yang.binding.BaseIdentity;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-
-import static org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.*;
+import static org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.setRoutingTable;
 
+import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
-import java.util.HashMap;
 
-import org.opendaylight.yangtools.yang.binding.DataContainer;
-import org.opendaylight.yangtools.yang.binding.RpcImplementation;
-import org.opendaylight.controller.md.sal.common.api.routing.MutableRoutingTable;
 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.binding.api.BindingAwareBroker.RoutedRpcRegistration;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
+import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter;
+import org.opendaylight.controller.sal.binding.api.rpc.RpcRoutingTable;
+import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper;
 import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.concepts.util.ListenerRegistry;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.RpcService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -66,11 +63,11 @@ public class RpcRouterCodegenInstance<T extends RpcService> implements //
         Map<Class<? extends BaseIdentity>, RpcRoutingTableImpl<? extends BaseIdentity, T>> mutableRoutingTables = new HashMap<>();
         for (Class<? extends BaseIdentity> ctx : contexts) {
             RpcRoutingTableImpl<? extends BaseIdentity, T> table = new RpcRoutingTableImpl<>(name,ctx,type);
-            
+
             @SuppressWarnings("rawtypes")
             Map invokerView = table.getRoutes();
-            
-            setRoutingTable((RpcService) invocationProxy, ctx, invokerView);
+
+            setRoutingTable(invocationProxy, ctx, invokerView);
             mutableRoutingTables.put(ctx, table);
             table.registerRouteChangeListener(this);
         }
index 500b1b399e8f38d5d51aa9b70ec14fc76ddd33cb..ce159b8f3ed0974b9e47300e1b0aa8a935596e3a 100644 (file)
@@ -7,24 +7,21 @@
  */
 package org.opendaylight.controller.sal.binding.codegen.impl;
 
-import org.opendaylight.controller.sal.binding.api.rpc.RpcRoutingTable;
-import org.opendaylight.yangtools.yang.binding.BaseIdentity;
-import org.opendaylight.yangtools.yang.binding.RpcService;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-
 import java.util.Collections;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher;
 import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher;
 import org.opendaylight.controller.md.sal.common.impl.routing.RoutingUtils;
+import org.opendaylight.controller.sal.binding.api.rpc.RpcRoutingTable;
 import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
-import org.opendaylight.yangtools.concepts.Identifiable;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.concepts.Mutable;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.RpcService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -44,7 +41,7 @@ implements //
 
     private RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>> listener;
     private S defaultRoute;
-    
+
     public RpcRoutingTableImpl(String routerName,Class<C> contextType, Class<S> serviceType) {
         super();
         this.routerName = routerName;
@@ -67,9 +64,9 @@ implements //
     @Override
     public <L extends RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>>> ListenerRegistration<L> registerRouteChangeListener(
             L listener) {
-        return (ListenerRegistration<L>) new SingletonListenerRegistration<L>(listener);
+        return new SingletonListenerRegistration<L>(listener);
     }
-        
+
     @Override
     public Class<C> getIdentifier() {
         return contextType;
@@ -79,7 +76,7 @@ implements //
     @SuppressWarnings("unchecked")
     public void updateRoute(InstanceIdentifier<?> path, S service) {
         S previous = this.routes.put(path, service);
-        
+
         LOGGER.debug("Route {} updated to {} in routing table {}",path,service,this);
         @SuppressWarnings("rawtypes")
         RouteChangeListener listenerCapture = listener;
@@ -88,7 +85,7 @@ implements //
         }
     }
 
-    
+
     @Override
     @SuppressWarnings("unchecked")
     public void removeRoute(InstanceIdentifier<?> path) {
@@ -100,7 +97,7 @@ implements //
             listenerCapture.onRouteChange(RoutingUtils.removalChange(contextType, path));
         }
     }
-    
+
     public void removeRoute(InstanceIdentifier<?> path, S service) {
         @SuppressWarnings("rawtypes")
         RouteChangeListener listenerCapture = listener;
@@ -123,12 +120,12 @@ implements //
     public Map<InstanceIdentifier<?>, S> getRoutes() {
         return unmodifiableRoutes;
     }
-    
+
     protected void removeAllReferences(S service) {
-        
+
     }
-    
-    
+
+
 
     @Override
     public String toString() {
index 244e3503439612fb7211dd9307c191e73f048120..a0bbb28d9e07624e23ad0afd094c347c27d2fce2 100644 (file)
@@ -9,9 +9,10 @@ package org.opendaylight.controller.sal.binding.codegen.impl;
 
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ThreadFactory;
 
+import javassist.ClassPool;
+
 import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator;
 import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory;
 
@@ -19,8 +20,6 @@ import com.google.common.util.concurrent.ListeningExecutorService;
 import com.google.common.util.concurrent.MoreExecutors;
 import com.google.common.util.concurrent.ThreadFactoryBuilder;
 
-import javassist.ClassPool;
-
 public class SingletonHolder {
 
     public static final ClassPool CLASS_POOL = new ClassPool();
@@ -30,6 +29,7 @@ public class SingletonHolder {
     public static final NotificationInvokerFactory INVOKER_FACTORY = RPC_GENERATOR_IMPL.getInvokerFactory();
     private static ListeningExecutorService NOTIFICATION_EXECUTOR = null;
     private static ListeningExecutorService COMMIT_EXECUTOR = null;
+    private static ListeningExecutorService CHANGE_EVENT_EXECUTOR = null;
 
     public static synchronized final ListeningExecutorService getDefaultNotificationExecutor() {
         if (NOTIFICATION_EXECUTOR == null) {
@@ -65,4 +65,21 @@ public class SingletonHolder {
         ExecutorService executor = Executors.newCachedThreadPool(factory);
         return MoreExecutors.listeningDecorator(executor);
     }
+
+    public static ExecutorService getDefaultChangeEventExecutor() {
+        if (CHANGE_EVENT_EXECUTOR == null) {
+            ThreadFactory factory = new ThreadFactoryBuilder().setDaemon(true).setNameFormat("md-sal-binding-change-%d").build();
+            /*
+             * FIXME: this used to be newCacheThreadPool(), but MD-SAL does not have transaction
+             *        ordering guarantees, which means that using a concurrent threadpool results
+             *        in application data being committed in random order, potentially resulting
+             *        in inconsistent data being present. Once proper primitives are introduced,
+             *        concurrency can be reintroduced.
+             */
+            ExecutorService executor = Executors.newSingleThreadExecutor(factory);
+            CHANGE_EVENT_EXECUTOR  = MoreExecutors.listeningDecorator(executor);
+        }
+
+        return CHANGE_EVENT_EXECUTOR;
+    }
 }
index 3cc66c30c10e490d1b652f6357d9b1ef308be3d2..16d5a24cb5b7c80364edd8dd5dbe4f8b59e6aa97 100644 (file)
@@ -7,28 +7,62 @@
  */
 package org.opendaylight.controller.sal.binding.impl;\r
 \r
-import java.util.Set;
-import java.util.concurrent.Future;\r
-import java.util.concurrent.atomic.AtomicLong;\r
-\r
-import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataBroker;\r
-import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;\r
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService;\r
-import org.opendaylight.controller.sal.binding.impl.util.BindingAwareDataReaderRouter;\r
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;\r
-import org.opendaylight.yangtools.yang.binding.DataObject;\r
-import org.opendaylight.yangtools.yang.binding.DataRoot;\r
-import org.opendaylight.yangtools.yang.binding.Identifiable;\r
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;\r
-import org.opendaylight.yangtools.yang.common.RpcResult;\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;
+import com.google.common.collect.ImmutableMap.Builder;
+import com.google.common.collect.Maps;
 \r
 \r
 public class DataBrokerImpl extends AbstractDataBroker<InstanceIdentifier<? extends DataObject>, DataObject, DataChangeListener> //\r
        implements DataProviderService, AutoCloseable {\r
 \r
+    private final static class ContainsWildcarded implements Predicate<InstanceIdentifier<? extends DataObject>> {
+
+        private final  InstanceIdentifier<? extends DataObject> key;
+
+        public ContainsWildcarded(InstanceIdentifier<? extends DataObject> key) {
+            this.key = key;
+        }
+
+        @Override
+        public boolean apply(InstanceIdentifier<? extends DataObject> input) {
+            return key.containsWildcarded(input);
+        }
+    }
+
+    private final static class IsContainedWildcarded implements Predicate<InstanceIdentifier<? extends DataObject>> {
+
+        private final  InstanceIdentifier<? extends DataObject> key;
+
+        public IsContainedWildcarded(InstanceIdentifier<? extends DataObject> key) {
+            this.key = key;
+        }
+
+        @Override
+        public boolean apply(InstanceIdentifier<? extends DataObject> input) {
+            return input.containsWildcarded(key);
+        }
+    }
+
     private final AtomicLong nextTransaction = new AtomicLong();\r
     private final AtomicLong createdTransactionsCount = new AtomicLong();\r
-    \r
+\r
     public AtomicLong getCreatedTransactionsCount() {\r
         return createdTransactionsCount;\r
     }\r
@@ -104,24 +138,40 @@ public class DataBrokerImpl extends AbstractDataBroker<InstanceIdentifier<? exte
             DataChangeListener changeListener) {\r
         throw new UnsupportedOperationException("Deprecated");\r
     }\r
-    \r
+\r
     @Override\r
     public void close() throws Exception {\r
-        \r
+\r
     }
-    
-    
+
     @Override
-    protected boolean isAffectedBy(InstanceIdentifier<? extends DataObject> key,
-            Set<InstanceIdentifier<? extends DataObject>> paths) {
-        if (paths.contains(key)) {
-            return true;
-        }
-        for (InstanceIdentifier<?> path : paths) {
-            if (key.containsWildcarded(path)) {
-                return true;
+    protected Predicate<InstanceIdentifier<? extends DataObject>> createContainsPredicate(final
+            InstanceIdentifier<? extends DataObject> key) {
+        return new ContainsWildcarded(key);
+    }
+
+    @Override
+    protected Predicate<InstanceIdentifier<? extends DataObject>> createIsContainedPredicate(final
+            InstanceIdentifier<? extends DataObject> key) {
+        return new IsContainedWildcarded(key);
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Override
+    protected Map<InstanceIdentifier<? extends DataObject>, DataObject> deepGetBySubpath(
+            Map<InstanceIdentifier<? extends DataObject>, DataObject> dataSet,
+            InstanceIdentifier<? extends DataObject> path) {
+        Builder<InstanceIdentifier<? extends DataObject>, DataObject> builder = ImmutableMap.builder();
+        Map<InstanceIdentifier<? extends DataObject>, DataObject> potential = Maps.filterKeys(dataSet, createIsContainedPredicate(path));
+        for(Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : potential.entrySet()) {
+            try {
+                builder.putAll(DataObjectReadingUtil.readData(entry.getValue(),(InstanceIdentifier)entry.getKey(),path));
+            } catch (Exception e) {
+                // FIXME : Log exception;
             }
         }
-        return false;
-    }\r
+        return builder.build();
+
+    }
+\r
 }
index 290ff2232f4f50236980486197eded7f52cfefea..1ea2eba87f932a565a7d537b8c41725c6ecfa8b8 100644 (file)
@@ -10,18 +10,17 @@ package org.opendaylight.controller.sal.binding.impl;
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataTransaction;
 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction.DataTransactionListener;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.concepts.util.ListenerRegistry;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
-public class DataTransactionImpl extends AbstractDataTransaction<InstanceIdentifier<? extends DataObject>, DataObject> 
+public class DataTransactionImpl extends AbstractDataTransaction<InstanceIdentifier<? extends DataObject>, DataObject>
     implements DataModificationTransaction {
     private final ListenerRegistry<DataTransactionListener> listeners = new ListenerRegistry<DataTransactionListener>();
-    
-    
-    
+
+
+
     public DataTransactionImpl(Object identifier,DataBrokerImpl dataBroker) {
         super(identifier,dataBroker);
     }
@@ -31,6 +30,7 @@ public class DataTransactionImpl extends AbstractDataTransaction<InstanceIdentif
         return listeners.register(listener);
     }
 
+    @Override
     protected void onStatusChange(TransactionStatus status) {
         for (ListenerRegistration<DataTransactionListener> listenerRegistration : listeners) {
             listenerRegistration.getInstance().onStatusUpdated(this, status);
index d997af59126833190b26696e752dfcc7061fe352..9a431fec74f4a3cf7c3f4d694f6c2000df3de718 100644 (file)
@@ -23,7 +23,10 @@ import org.opendaylight.yangtools.yang.binding.Notification
 import org.slf4j.LoggerFactory\r
 import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder\rimport com.google.common.collect.Multimaps\r
 import org.opendaylight.yangtools.concepts.util.ListenerRegistry\r
-import org.opendaylight.controller.sal.binding.api.NotificationProviderService.NotificationInterestListener\r
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService.NotificationInterestListener\rimport java.util.Set\r
+import java.util.Set\r
+import com.google.common.collect.ImmutableSet\r
+import java.util.concurrent.Future\r
 \r
 class NotificationBrokerImpl implements NotificationProviderService, AutoCloseable {\r
     \r
@@ -100,9 +103,17 @@ class NotificationBrokerImpl implements NotificationProviderService, AutoCloseab
             listenerToNotify = listenerToNotify + listeners.get(type as Class<? extends Notification>)\r
         }\r
         val tasks = listenerToNotify.map[new NotifyTask(it, notification)].toSet;\r
-        executor.invokeAll(tasks);\r
+        submitAll(executor,tasks);\r
     }\r
-\r
+    \r
+    def submitAll(ExecutorService service, Set<NotifyTask> tasks) {\r
+        val ret = ImmutableSet.<Future<Object>>builder();\r
+        for(task : tasks) {\r
+            ret.add(service.submit(task));\r
+        }\r
+        return ret.build();\r
+    }\r
+    \r
     override <T extends Notification> registerNotificationListener(Class<T> notificationType,\r
         NotificationListener<T> listener) {\r
         val reg = new GenericNotificationRegistration<T>(notificationType, listener, this);\r
index 5292487d032b28f0b5c217dfb202807393dd60c7..3ad1dabffe0b39958b65019274b459fae167d8bb 100644 (file)
@@ -7,8 +7,7 @@
  */
 package org.opendaylight.controller.sal.binding.impl;
 
-import static com.google.common.base.Preconditions.checkState;
-
+import com.google.common.collect.ImmutableClassToInstanceMap;
 import org.opendaylight.controller.md.sal.binding.util.AbstractBindingSalProviderInstance;
 import org.opendaylight.controller.md.sal.binding.util.BindingContextUtils;
 import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
@@ -33,8 +32,7 @@ import org.opendaylight.yangtools.yang.binding.RpcService;
 import org.osgi.framework.BundleContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-
-import com.google.common.collect.ImmutableClassToInstanceMap;
+import static com.google.common.base.Preconditions.checkState;
 
 public class RootBindingAwareBroker implements //
         Mutable, //
index f93457110181967063ec64c27a3f29c026320121..e98d5b9942c86afb9b76e006662fe02cdf6147c2 100644 (file)
@@ -7,29 +7,28 @@
  */
 package org.opendaylight.controller.sal.binding.impl;
 
+import static com.google.common.base.Preconditions.checkState;
+
 import java.util.EventListener;
+import java.util.HashMap;
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.HashMap;
 import java.util.Set;
 import java.util.WeakHashMap;
 
-import javax.swing.tree.ExpandVetoException;
-
 import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
 import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
 import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher;
 import org.opendaylight.controller.md.sal.common.impl.routing.RoutingUtils;
-import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier;
 import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter;
 import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator;
 import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper;
 import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder;
-import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier;
 import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
-import org.opendaylight.yangtools.concepts.Identifiable;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.concepts.util.ListenerRegistry;
 import org.opendaylight.yangtools.yang.binding.BaseIdentity;
@@ -38,8 +37,6 @@ import org.opendaylight.yangtools.yang.binding.RpcService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import static com.google.common.base.Preconditions.*;
-
 public class RpcProviderRegistryImpl implements //
         RpcProviderRegistry, //
         RouteChangePublisher<RpcContextIdentifier, InstanceIdentifier<?>> {
@@ -56,7 +53,7 @@ public class RpcProviderRegistryImpl implements //
 
     private final String name;
 
-    private ListenerRegistry<GlobalRpcRegistrationListener> globalRpcListeners = ListenerRegistry.create();
+    private final ListenerRegistry<GlobalRpcRegistrationListener> globalRpcListeners = ListenerRegistry.create();
 
     public String getName() {
         return name;
@@ -96,7 +93,6 @@ public class RpcProviderRegistryImpl implements //
     @Override
     public final <T extends RpcService> T getRpcService(Class<T> type) {
 
-        @SuppressWarnings("unchecked")
         T potentialProxy = (T) publicProxies.get(type);
         if (potentialProxy != null) {
             return potentialProxy;
@@ -109,7 +105,7 @@ public class RpcProviderRegistryImpl implements //
 
             potentialProxy = (T) publicProxies.get(type);
             if (potentialProxy != null) {
-                return (T) potentialProxy;
+                return potentialProxy;
             }
             T proxy = rpcFactory.getDirectProxyFor(type);
             LOG.debug("Created {} as public proxy for {} in {}", proxy, type.getSimpleName(), this);
@@ -151,10 +147,10 @@ public class RpcProviderRegistryImpl implements //
                 LOG.error("Unhandled exception during invoking listener {}", e);
             }
         }
-        
+
     }
 
-    private void notifyListenersRoutedCreated(RpcRouter router) {
+    private void notifyListenersRoutedCreated(RpcRouter<?> router) {
 
         for (ListenerRegistration<RouterInstantiationListener> listener : routerInstantiationListener) {
             try {
@@ -196,7 +192,7 @@ public class RpcProviderRegistryImpl implements //
     public interface RouterInstantiationListener extends EventListener {
         void onRpcRouterCreated(RpcRouter<?> router);
     }
-    
+
     public ListenerRegistration<GlobalRpcRegistrationListener> registerGlobalRpcRegistrationListener(GlobalRpcRegistrationListener listener) {
         return globalRpcListeners.register(listener);
     }
@@ -204,7 +200,7 @@ public class RpcProviderRegistryImpl implements //
     public interface GlobalRpcRegistrationListener extends EventListener {
         void onGlobalRpcRegistered(Class<? extends RpcService> cls);
         void onGlobalRpcUnregistered(Class<? extends RpcService> cls);
-        
+
     }
 
     private class RouteChangeForwarder<T extends RpcService> implements
index 5630664a678e8387426bb6a2b2ff88957b0654e8..e48ebbc0577f1b6101a772284ba9e07b3e6580cf 100644 (file)
@@ -45,8 +45,6 @@ import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
 import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider;
 import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier;
 import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter;
-import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
-import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
 import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl;
 import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl.GlobalRpcRegistrationListener;
 import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl.RouterInstantiationListener;
@@ -79,6 +77,8 @@ import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.data.api.Node;
 import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
+import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
+import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -113,11 +113,11 @@ public class BindingIndependentConnector implements //
 
     private DataProviderService baDataService;
 
-    private ConcurrentMap<Object, BindingToDomTransaction> domOpenedTransactions = new ConcurrentHashMap<>();
-    private ConcurrentMap<Object, DomToBindingTransaction> bindingOpenedTransactions = new ConcurrentHashMap<>();
+    private final ConcurrentMap<Object, BindingToDomTransaction> domOpenedTransactions = new ConcurrentHashMap<>();
+    private final ConcurrentMap<Object, DomToBindingTransaction> bindingOpenedTransactions = new ConcurrentHashMap<>();
 
-    private BindingToDomCommitHandler bindingToDomCommitHandler = new BindingToDomCommitHandler();
-    private DomToBindingCommitHandler domToBindingCommitHandler = new DomToBindingCommitHandler();
+    private final BindingToDomCommitHandler bindingToDomCommitHandler = new BindingToDomCommitHandler();
+    private final DomToBindingCommitHandler domToBindingCommitHandler = new DomToBindingCommitHandler();
 
     private Registration<DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject>> baCommitHandlerRegistration;
 
@@ -130,7 +130,7 @@ public class BindingIndependentConnector implements //
     // private ListenerRegistration<BindingToDomRpcForwardingManager>
     // bindingToDomRpcManager;
 
-    private Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> toDOMInstanceIdentifier = new Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier>() {
+    private final Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> toDOMInstanceIdentifier = new Function<InstanceIdentifier<?>, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier>() {
 
         @Override
         public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier apply(InstanceIdentifier<?> input) {
@@ -149,8 +149,6 @@ public class BindingIndependentConnector implements //
 
     private RpcProviderRegistryImpl baRpcRegistryImpl;
 
-    private org.opendaylight.controller.sal.dom.broker.spi.RpcRouter biRouter;
-
     private NotificationProviderService baNotifyService;
 
     private NotificationPublishService domNotificationService;
@@ -319,9 +317,6 @@ public class BindingIndependentConnector implements //
                 baRpcRegistryImpl.registerRouterInstantiationListener(domToBindingRpcManager.getInstance());
                 baRpcRegistryImpl.registerGlobalRpcRegistrationListener(domToBindingRpcManager.getInstance());
             }
-            if (biRpcRegistry instanceof org.opendaylight.controller.sal.dom.broker.spi.RpcRouter) {
-                biRouter = (org.opendaylight.controller.sal.dom.broker.spi.RpcRouter) biRpcRegistry;
-            }
             rpcForwarding = true;
         }
     }
@@ -413,8 +408,8 @@ public class BindingIndependentConnector implements //
     private class BindingToDomTransaction implements
             DataCommitTransaction<InstanceIdentifier<? extends DataObject>, DataObject> {
 
-        private DataModificationTransaction backing;
-        private DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification;
+        private final DataModificationTransaction backing;
+        private final DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification;
 
         public BindingToDomTransaction(DataModificationTransaction backing,
                 DataModification<InstanceIdentifier<? extends DataObject>, DataObject> modification) {
@@ -491,6 +486,7 @@ public class BindingIndependentConnector implements //
             // FIXME: do registration based on only active commit handlers.
         }
 
+        @Override
         public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> requestCommit(
                 DataModification<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> domTransaction) {
             Object identifier = domTransaction.getIdentifier();
@@ -587,9 +583,9 @@ public class BindingIndependentConnector implements //
 
         private final Set<QName> supportedRpcs;
         private final WeakReference<Class<? extends RpcService>> rpcServiceType;
-        private Set<org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration> registrations;
-        private Map<QName, RpcInvocationStrategy> strategiesByQName = new HashMap<>();
-        private WeakHashMap<Method, RpcInvocationStrategy> strategiesByMethod = new WeakHashMap<>();
+        private final Set<org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration> registrations;
+        private final Map<QName, RpcInvocationStrategy> strategiesByQName = new HashMap<>();
+        private final WeakHashMap<Method, RpcInvocationStrategy> strategiesByMethod = new WeakHashMap<>();
 
         public DomToBindingRpcForwarder(Class<? extends RpcService> service) {
             this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
@@ -771,10 +767,10 @@ public class BindingIndependentConnector implements //
     private class DefaultInvocationStrategy extends RpcInvocationStrategy {
 
         @SuppressWarnings("rawtypes")
-        private WeakReference<Class> inputClass;
+        private final WeakReference<Class> inputClass;
 
         @SuppressWarnings("rawtypes")
-        private WeakReference<Class> outputClass;
+        private final WeakReference<Class> outputClass;
 
         @SuppressWarnings({ "rawtypes", "unchecked" })
         public DefaultInvocationStrategy(QName rpc, Method targetMethod, Class<?> outputClass,
@@ -803,10 +799,10 @@ public class BindingIndependentConnector implements //
 
         @Override
         public Future<RpcResult<?>> forwardToDomBroker(DataObject input) {
-            if(biRouter != null) {
+            if(biRpcRegistry != null) {
                 CompositeNode xml = mappingService.toDataDom(input);
                 CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc, ImmutableList.<Node<?>> of(xml));
-                RpcResult<CompositeNode> result = biRouter.invokeRpc(rpc, wrappedXml);
+                RpcResult<CompositeNode> result = biRpcRegistry.invokeRpc(rpc, wrappedXml);
                 Object baResultValue = null;
                 if (result.getResult() != null) {
                     baResultValue = mappingService.dataObjectFromDataDom(outputClass.get(), result.getResult());
@@ -825,6 +821,7 @@ public class BindingIndependentConnector implements //
             super(rpc, targetMethod);
         }
 
+        @Override
         public RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception {
             @SuppressWarnings("unchecked")
             Future<RpcResult<Void>> result = (Future<RpcResult<Void>>) targetMethod.invoke(rpcService);
@@ -837,21 +834,21 @@ public class BindingIndependentConnector implements //
             return Futures.immediateFuture(null);
         }
     }
-    
+
     private class NoOutputInvocationStrategy extends RpcInvocationStrategy {
 
-        
+
         @SuppressWarnings("rawtypes")
-        private WeakReference<Class> inputClass;
+        private final WeakReference<Class> inputClass;
 
         @SuppressWarnings({ "rawtypes", "unchecked" })
-        public NoOutputInvocationStrategy(QName rpc, Method targetMethod, 
+        public NoOutputInvocationStrategy(QName rpc, Method targetMethod,
                 Class<? extends DataContainer> inputClass) {
             super(rpc,targetMethod);
             this.inputClass = new WeakReference(inputClass);
         }
-        
-        
+
+
         @Override
         public RpcResult<CompositeNode> uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception {
             DataContainer bindingInput = mappingService.dataObjectFromDataDom(inputClass.get(), domInput);
@@ -865,10 +862,10 @@ public class BindingIndependentConnector implements //
 
         @Override
         public Future<RpcResult<?>> forwardToDomBroker(DataObject input) {
-            if(biRouter != null) {
+            if(biRpcRegistry != null) {
                 CompositeNode xml = mappingService.toDataDom(input);
                 CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc,ImmutableList.<Node<?>>of(xml));
-                RpcResult<CompositeNode> result = biRouter.invokeRpc(rpc, wrappedXml);
+                RpcResult<CompositeNode> result = biRpcRegistry.invokeRpc(rpc, wrappedXml);
                 Object baResultValue = null;
                 RpcResult<?> baResult = Rpcs.<Void>getRpcResult(result.isSuccessful(), null, result.getErrors());
                 return Futures.<RpcResult<?>>immediateFuture(baResult);
@@ -902,12 +899,12 @@ public class BindingIndependentConnector implements //
     public void setDomNotificationService(NotificationPublishService domService) {
         this.domNotificationService = domService;
     }
-    
+
     private class DomToBindingNotificationForwarder implements NotificationInterestListener, NotificationListener {
 
-        private ConcurrentMap<QName, WeakReference<Class<? extends Notification>>> notifications = new ConcurrentHashMap<>();
-        private Set<QName> supportedNotifications = new HashSet<>();
-        
+        private final ConcurrentMap<QName, WeakReference<Class<? extends Notification>>> notifications = new ConcurrentHashMap<>();
+        private final Set<QName> supportedNotifications = new HashSet<>();
+
         @Override
         public Set<QName> getSupportedNotifications() {
             return Collections.unmodifiableSet(supportedNotifications);
@@ -922,7 +919,7 @@ public class BindingIndependentConnector implements //
                 if (potentialClass != null) {
                     final DataContainer baNotification = mappingService.dataObjectFromDataDom(potentialClass,
                             notification);
-                    
+
                     if (baNotification instanceof Notification) {
                         baNotifyService.publish((Notification) baNotification);
                     }
index e89797ca2daa2f8267ffeedb7e0f7fecb976d321..8278b365518e2cd62ee400fe14693e7b18cef96a 100644 (file)
@@ -13,19 +13,13 @@ import java.util.concurrent.ConcurrentMap;
 import org.opendaylight.controller.md.sal.common.api.data.DataModification;
 import org.opendaylight.yangtools.concepts.Path;
 
-import com.google.common.util.concurrent.JdkFutureAdapters;
-
 public final class DataModificationTracker<P extends Path<P>,D> {
-
     ConcurrentMap<Object, DataModification<P,D>> trackedTransactions = new ConcurrentHashMap<>();
-    
-    
+
     public void startTrackingModification(DataModification<P,D> modification) {
         trackedTransactions.putIfAbsent(modification.getIdentifier(), modification);
-        
-        
     }
-    
+
     public boolean containsIdentifier(Object identifier) {
         return trackedTransactions.containsKey(identifier);
     }
index 7c38ff2731805d0bf57dc590d588f863da7a307b..6c80f4d7394947cd34af1aa3eedb305dc2f99113 100644 (file)
@@ -10,12 +10,11 @@ package org.opendaylight.controller.sal.binding.test;
 import org.junit.After;
 import org.junit.Before;
 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
-import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
 import org.opendaylight.controller.sal.binding.test.util.BindingBrokerTestFactory;
 import org.opendaylight.controller.sal.binding.test.util.BindingTestContext;
 import org.opendaylight.controller.sal.core.api.data.DataStore;
 import org.opendaylight.controller.sal.dom.broker.impl.DataStoreStatsWrapper;
-import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore;
+import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
index 76abd833e9337bba87595956f0d4f82993009d61..4afbc298426e943810f8149a0d17a20ae9e93210 100644 (file)
@@ -7,22 +7,20 @@
  */
 package org.opendaylight.controller.sal.binding.test;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 import javassist.ClassPool;
 
 import org.junit.Before;
 import org.junit.Test;
-
-import static org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.*;
-
-import org.opendaylight.controller.sal.binding.api.NotificationListener;
 import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter;
 import org.opendaylight.controller.sal.binding.api.rpc.RpcRoutingTable;
 import org.opendaylight.controller.sal.binding.codegen.impl.RuntimeCodeGenerator;
@@ -30,12 +28,10 @@ import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory;
 import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory.NotificationInvoker;
 import org.opendaylight.controller.sal.binding.test.mock.BarListener;
 import org.opendaylight.controller.sal.binding.test.mock.BarUpdate;
-import org.opendaylight.controller.sal.binding.test.mock.CompositeListener;
 import org.opendaylight.controller.sal.binding.test.mock.FlowDelete;
 import org.opendaylight.controller.sal.binding.test.mock.FooListener;
 import org.opendaylight.controller.sal.binding.test.mock.FooService;
 import org.opendaylight.controller.sal.binding.test.mock.FooUpdate;
-import org.opendaylight.controller.sal.binding.test.mock.InheritedContextInput;
 import org.opendaylight.controller.sal.binding.test.mock.ReferencableObject;
 import org.opendaylight.controller.sal.binding.test.mock.ReferencableObjectKey;
 import org.opendaylight.controller.sal.binding.test.mock.SimpleInput;
@@ -47,8 +43,6 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
 
-import static org.mockito.Mockito.*;
-
 public class RuntimeCodeGeneratorTest {
 
     private RuntimeCodeGenerator codeGenerator;
@@ -84,7 +78,7 @@ public class RuntimeCodeGeneratorTest {
 
         NotificationInvoker invokerFoo = invokerFactory.invokerFor(fooListener);
 
-        
+
         assertSame(fooListener,invokerFoo.getDelegate());
         assertNotNull(invokerFoo.getSupportedNotifications());
         assertEquals(1, invokerFoo.getSupportedNotifications().size());
index 7ab489a9f59f993af6a993e918115d830fdde9a8..68d7f6cd9efd510e269f791951da082e6a98c6dd 100644 (file)
@@ -10,9 +10,9 @@ package org.opendaylight.controller.sal.binding.test.mock;
 import org.opendaylight.yangtools.yang.binding.Identifier;
 
 public class ReferencableObjectKey implements Identifier<ReferencableObject> {
-
+    private static final long serialVersionUID = 1L;
     final Integer value;
-    
+
     public ReferencableObjectKey(Integer _value) {
         this.value = _value;
     }
@@ -46,6 +46,6 @@ public class ReferencableObjectKey implements Identifier<ReferencableObject> {
     public String toString() {
         return "ReferencableObjectKey [value=" + value + "]";
     }
-    
-    
+
+
 }
index 2b0865ae46e0f01045bf4037a06988a77a057158..e5b57e3668baadb6fbe942364bfb3d920f56772c 100644 (file)
@@ -11,11 +11,6 @@ import java.util.concurrent.ExecutorService;
 
 import javassist.ClassPool;
 
-import org.opendaylight.controller.sal.core.api.data.DataStore;
-import org.opendaylight.controller.sal.dom.broker.impl.DataStoreStatsWrapper;
-import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore;
-import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter;
-
 import com.google.common.base.Preconditions;
 import com.google.common.util.concurrent.ListeningExecutorService;
 import com.google.common.util.concurrent.MoreExecutors;
@@ -27,7 +22,7 @@ public class BindingBrokerTestFactory {
     private ExecutorService executor;
     private ClassPool classPool;
 
-    
+
     public boolean isStartWithParsedSchema() {
         return startWithParsedSchema;
     }
@@ -55,7 +50,7 @@ public class BindingBrokerTestFactory {
         if(classPool == null) {
             return CLASS_POOL;
         }
-        
+
         return classPool;
     }
 
index ec8c8372c1446989f4b1c96477d5e38b1fff76d7..d016754385d1b4ee53e2feb512a75e460b6b37db 100644 (file)
@@ -7,6 +7,10 @@
  */
 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.assertNull;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -15,17 +19,10 @@ import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
-
-
-
-
-
-
-
 import org.junit.Test;
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
-import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PopMplsActionCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.pop.mpls.action._case.PopMplsActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
@@ -40,15 +37,13 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instru
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.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.match.layer._3.match.Ipv4MatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder;
 import org.opendaylight.yangtools.yang.binding.DataObject;
@@ -63,8 +58,6 @@ import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.ListeningExecutorService;
 import com.google.common.util.concurrent.MoreExecutors;
 
-import static org.junit.Assert.*;
-
 public class DOMCodecBug01Test extends AbstractDataServiceTest {
 
     private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
@@ -182,7 +175,7 @@ public class DOMCodecBug01Test extends AbstractDataServiceTest {
         flow.setNode(NODE_REF);
         InstructionsBuilder instructions = new InstructionsBuilder();
         InstructionBuilder instruction = new InstructionBuilder();
-        
+
         instruction.setOrder(10);
         ApplyActionsBuilder applyActions = new ApplyActionsBuilder();
         List<Action> actionList = new ArrayList<>();
@@ -204,7 +197,7 @@ public class DOMCodecBug01Test extends AbstractDataServiceTest {
         assertNotNull(ret);
         assertEquals(TransactionStatus.COMMITED, ret.getResult());
     }
-    
+
     private void createFlow2() throws Exception {
         DataModificationTransaction modification = baDataService.beginTransaction();
         long id = 123;
@@ -215,7 +208,7 @@ public class DOMCodecBug01Test extends AbstractDataServiceTest {
         MatchBuilder match = new MatchBuilder();
         match.setLayer4Match(new TcpMatchBuilder().build());
         flow.setMatch(match.build());
-        
+
         path1 = InstanceIdentifier.builder(Flows.class).child(Flow.class, key).toInstance();
        // DataObject cls = (DataObject) modification.readConfigurationData(path1);
         modification.putConfigurationData(path1, flow.build());
index 929eb66350115f025135dc77b5ce1aaf4d103149..9d604406983b5bd3a7bb18b875d626a0d77e697c 100644 (file)
@@ -7,6 +7,9 @@
  */
 package org.opendaylight.controller.sal.binding.test.bugfix;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
 import java.util.Collections;
 import java.util.Map;
 import java.util.concurrent.Callable;
@@ -16,29 +19,24 @@ import java.util.concurrent.Future;
 
 import javassist.ClassPool;
 
-import org.junit.Ignore;
 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.controller.sal.binding.test.util.BindingBrokerTestFactory;
-import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
 import com.google.common.util.concurrent.ListeningExecutorService;
 import com.google.common.util.concurrent.MoreExecutors;
 
-import static org.junit.Assert.*;
-
 public class DOMCodecBug02Test extends AbstractDataServiceTest {
 
     private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
@@ -70,10 +68,11 @@ public class DOMCodecBug02Test extends AbstractDataServiceTest {
     /**
      * This test is ignored, till found out better way to test generation
      * of classes without leaking of instances from previous run
-     * 
+     *
      * @throws Exception
      */
-    
+
+    @Override
     public void setUp() {
         ListeningExecutorService executor = MoreExecutors.sameThreadExecutor();
         BindingBrokerTestFactory factory = new BindingBrokerTestFactory();
@@ -82,13 +81,13 @@ public class DOMCodecBug02Test extends AbstractDataServiceTest {
         factory.setStartWithParsedSchema(getStartWithSchema());
         testContext = factory.getTestContext();
         testContext.start();
-        
+
         baDataService = testContext.getBindingDataBroker();
         biDataService = testContext.getDomDataBroker();
         dataStore = testContext.getDomDataStore();
         mappingService = testContext.getBindingToDomMappingService();
     };
-    
+
     @Test
     public void testSchemaContextNotAvailable() throws Exception {
 
@@ -104,11 +103,11 @@ public class DOMCodecBug02Test extends AbstractDataServiceTest {
                 return transaction.commit();
             }
         });
-        
-        
+
+
         RpcResult<TransactionStatus> result = future.get().get();
         assertEquals(TransactionStatus.COMMITED, result.getResult());
-        
+
         Nodes nodes = checkForNodes();
         assertNotNull(nodes);
 
@@ -118,7 +117,7 @@ public class DOMCodecBug02Test extends AbstractDataServiceTest {
         return (Nodes) baDataService.readOperationalData(NODES_INSTANCE_ID_BA);
 
     }
-    
+
     @Override
     protected boolean getStartWithSchema() {
         return false;
index f2576e9960614e74d2889987793b8e3694f1f726..6a050efb35679af9ef283bbef313a09cc92b24d9 100644 (file)
@@ -6,7 +6,11 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 package org.opendaylight.controller.sal.binding.test.bugfix;
-import java.util.Arrays;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -14,35 +18,31 @@ import java.util.Map;
 import org.junit.Test;
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
-import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
 import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SupportedActions;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SupportedActionsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.supported.actions.ActionType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.supported.actions.ActionTypeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.SupportType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.SupportType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesKey;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 
-import static org.junit.Assert.*;
-
 public class DOMCodecBug03Test extends AbstractDataServiceTest implements DataChangeListener {
 
     private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
@@ -60,15 +60,15 @@ public class DOMCodecBug03Test extends AbstractDataServiceTest implements DataCh
     private static final InstanceIdentifier<Node> NODE_INSTANCE_ID_BA = InstanceIdentifier//
             .builder(NODES_INSTANCE_ID_BA) //
             .child(Node.class, NODE_KEY).toInstance();
-    
-    
+
+
     private static final InstanceIdentifier<SupportedActions> SUPPORTED_ACTIONS_INSTANCE_ID_BA = InstanceIdentifier//
             .builder(NODES_INSTANCE_ID_BA) //
             .child(Node.class, NODE_KEY) //
             .augmentation(FlowCapableNode.class) //
             .child(SupportedActions.class)
             .toInstance();
-    
+
 
     private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODE_INSTANCE_ID_BI = //
     org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
@@ -77,35 +77,35 @@ public class DOMCodecBug03Test extends AbstractDataServiceTest implements DataCh
             .toInstance();
     private static final QName SUPPORTED_ACTIONS_QNAME = QName.create(FlowCapableNode.QNAME, SupportedActions.QNAME.getLocalName());
 
-    
+
     private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier SUPPORTED_ACTIONS_INSTANCE_ID_BI = //
             org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
                     .node(Nodes.QNAME) //
                     .nodeWithKey(Node.QNAME, NODE_KEY_BI) //
                     .node(SUPPORTED_ACTIONS_QNAME) //
                     .toInstance();
-    
+
     private DataChangeEvent<InstanceIdentifier<?>, DataObject> receivedChangeEvent;
 
-    
-    
+
+
     /**
      * Test for Bug 148
-     * 
+     *
      * @throws Exception
      */
     @Test
     public void testAugmentSerialization() throws Exception {
 
-        
+
         baDataService.registerDataChangeListener(NODES_INSTANCE_ID_BA, this);
-        
+
         NodeBuilder nodeBuilder = new NodeBuilder();
         nodeBuilder.setId(new NodeId(NODE_ID));
         nodeBuilder.setKey(NODE_KEY);
         DataModificationTransaction transaction = baDataService.beginTransaction();
-        
-        
+
+
         FlowCapableNodeBuilder fnub = new FlowCapableNodeBuilder();
         fnub.setHardware("Hardware Foo");
         fnub.setManufacturer("Manufacturer Foo");
@@ -116,47 +116,47 @@ public class DOMCodecBug03Test extends AbstractDataServiceTest implements DataCh
         nodeBuilder.addAugmentation(FlowCapableNode.class, fnu);
         Node original = nodeBuilder.build();
         transaction.putOperationalData(NODE_INSTANCE_ID_BA, original);
-        
+
         RpcResult<TransactionStatus> result = transaction.commit().get();
         assertEquals(TransactionStatus.COMMITED, result.getResult());
-        
+
         assertNotNull(receivedChangeEvent);
-        
+
         verifyNodes((Nodes) receivedChangeEvent.getUpdatedOperationalSubtree(),original);
         assertBindingIndependentVersion(NODE_INSTANCE_ID_BI);
         Nodes nodes = checkForNodes();
         verifyNodes(nodes,original);
-        
+
         testAddingNodeConnector();
         testNodeRemove();
 
     }
-    
+
     @Test
     public void testAugmentNestedSerialization() throws Exception {
         DataModificationTransaction transaction = baDataService.beginTransaction();
-        
+
         SupportedActionsBuilder actions = new SupportedActionsBuilder();
         ActionTypeBuilder action = new ActionTypeBuilder();
         action.setAction("foo-action");
         action.setSupportState(SupportType.Native);
         List<ActionType> actionTypes = Collections.singletonList(action.build());
         actions.setActionType(actionTypes );
-        
+
         transaction.putOperationalData(SUPPORTED_ACTIONS_INSTANCE_ID_BA, actions.build());
         RpcResult<TransactionStatus> putResult = transaction.commit().get();
         assertNotNull(putResult);
         assertEquals(TransactionStatus.COMMITED, putResult.getResult());
         SupportedActions readedTable = (SupportedActions) baDataService.readOperationalData(SUPPORTED_ACTIONS_INSTANCE_ID_BA);
         assertNotNull(readedTable);
-        
+
         CompositeNode biSupportedActions = biDataService.readOperationalData(SUPPORTED_ACTIONS_INSTANCE_ID_BI);
         assertNotNull(biSupportedActions);
-        
+
     }
 
     private void testAddingNodeConnector() throws Exception {
-        
+
         NodeConnectorId ncId = new NodeConnectorId("openflow:1:bar");
         NodeConnectorKey nodeKey = new NodeConnectorKey(ncId );
         InstanceIdentifier<NodeConnector> ncInstanceId = InstanceIdentifier.builder(NODE_INSTANCE_ID_BA).child(NodeConnector.class, nodeKey).toInstance();
@@ -181,7 +181,7 @@ public class DOMCodecBug03Test extends AbstractDataServiceTest implements DataCh
         transaction.removeOperationalData(NODE_INSTANCE_ID_BA);
         RpcResult<TransactionStatus> result = transaction.commit().get();
         assertEquals(TransactionStatus.COMMITED, result.getResult());
-        
+
         Node node = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA);
         assertNull(node);
     }
@@ -193,13 +193,13 @@ public class DOMCodecBug03Test extends AbstractDataServiceTest implements DataCh
         Node readedNode = nodes.getNode().get(0);
         assertEquals(original.getId(), readedNode.getId());
         assertEquals(original.getKey(), readedNode.getKey());
-        
+
         FlowCapableNode fnu = original.getAugmentation(FlowCapableNode.class);
         FlowCapableNode readedAugment = readedNode.getAugmentation(FlowCapableNode.class);
         assertNotNull(fnu);
         assertEquals(fnu.getDescription(), readedAugment.getDescription());
         assertEquals(fnu.getSerialNumber(), readedAugment.getSerialNumber());
-        
+
     }
 
     private void assertBindingIndependentVersion(
@@ -211,7 +211,7 @@ public class DOMCodecBug03Test extends AbstractDataServiceTest implements DataCh
     private Nodes checkForNodes() {
         return (Nodes) baDataService.readOperationalData(NODES_INSTANCE_ID_BA);
     }
-    
+
     @Override
     public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
         receivedChangeEvent = change;
index 8003e37e4e193f1685c3f0cc452e85b257140831..90fa2be21103a7bf89ec8191a2a4d9fad4b301f4 100644 (file)
@@ -6,46 +6,41 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 package org.opendaylight.controller.sal.binding.test.bugfix;
-import java.util.Arrays;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
 import java.util.Collections;
-import java.util.List;
 import java.util.Map;
 
 import org.junit.Test;
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
-import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
 import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SupportedActions;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SupportedActionsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.supported.actions.ActionType;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.supported.actions.ActionTypeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.SupportType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesKey;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 
-import static org.junit.Assert.*;
-
 public class PutAugmentationTest extends AbstractDataServiceTest implements DataChangeListener {
 
     private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
@@ -59,49 +54,54 @@ public class PutAugmentationTest extends AbstractDataServiceTest implements Data
     private static final InstanceIdentifier<Nodes> NODES_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) //
             .toInstance();
 
-
     private static final InstanceIdentifier<Node> NODE_INSTANCE_ID_BA = InstanceIdentifier//
             .builder(NODES_INSTANCE_ID_BA) //
             .child(Node.class, NODE_KEY).toInstance();
-    
-    
+
     private static final InstanceIdentifier<SupportedActions> SUPPORTED_ACTIONS_INSTANCE_ID_BA = InstanceIdentifier//
             .builder(NODES_INSTANCE_ID_BA) //
             .child(Node.class, NODE_KEY) //
             .augmentation(FlowCapableNode.class) //
-            .child(SupportedActions.class)
-            .toInstance();
-    
+            .child(SupportedActions.class).toInstance();
+
+    private static final InstanceIdentifier<FlowCapableNode> ALL_FLOW_CAPABLE_NODES = InstanceIdentifier //
+            .builder(NODES_INSTANCE_ID_BA) //
+            .child(Node.class) //
+            .augmentation(FlowCapableNode.class) //
+            .build();
 
     private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODE_INSTANCE_ID_BI = //
     org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
             .node(Nodes.QNAME) //
             .nodeWithKey(Node.QNAME, NODE_KEY_BI) //
             .toInstance();
-    private static final QName SUPPORTED_ACTIONS_QNAME = QName.create(FlowCapableNode.QNAME, SupportedActions.QNAME.getLocalName());
+    private static final QName SUPPORTED_ACTIONS_QNAME = QName.create(FlowCapableNode.QNAME,
+            SupportedActions.QNAME.getLocalName());
 
-    
     private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier SUPPORTED_ACTIONS_INSTANCE_ID_BI = //
-            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
-                    .node(Nodes.QNAME) //
-                    .nodeWithKey(Node.QNAME, NODE_KEY_BI) //
-                    .node(SUPPORTED_ACTIONS_QNAME) //
-                    .toInstance();
-    
-    private DataChangeEvent<InstanceIdentifier<?>, DataObject> receivedChangeEvent;
-
-    
-    
+    org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() //
+            .node(Nodes.QNAME) //
+            .nodeWithKey(Node.QNAME, NODE_KEY_BI) //
+            .node(SUPPORTED_ACTIONS_QNAME) //
+            .toInstance();
+    private static final InstanceIdentifier<FlowCapableNode> FLOW_AUGMENTATION_PATH = InstanceIdentifier //
+            .builder(NODE_INSTANCE_ID_BA) //
+            .augmentation(FlowCapableNode.class) //
+            .build();
+
+    private DataChangeEvent<InstanceIdentifier<?>, DataObject> lastReceivedChangeEvent;
+
     /**
      * Test for Bug 148
-     * 
+     *
      * @throws Exception
      */
     @Test
     public void putNodeAndAugmentation() throws Exception {
 
-        baDataService.registerDataChangeListener(NODES_INSTANCE_ID_BA, this);
-        
+        baDataService.registerDataChangeListener(ALL_FLOW_CAPABLE_NODES, this);
+
+
         NodeBuilder nodeBuilder = new NodeBuilder();
         nodeBuilder.setId(new NodeId(NODE_ID));
         nodeBuilder.setKey(NODE_KEY);
@@ -109,11 +109,11 @@ public class PutAugmentationTest extends AbstractDataServiceTest implements Data
         baseTransaction.putOperationalData(NODE_INSTANCE_ID_BA, nodeBuilder.build());
         RpcResult<TransactionStatus> result = baseTransaction.commit().get();
         assertEquals(TransactionStatus.COMMITED, result.getResult());
-        assertNotNull(receivedChangeEvent);
+
         Node node = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA);
         assertNotNull(node);
         assertEquals(NODE_KEY, node.getKey());
-        
+
         FlowCapableNodeBuilder fnub = new FlowCapableNodeBuilder();
         fnub.setHardware("Hardware Foo");
         fnub.setManufacturer("Manufacturer Foo");
@@ -121,14 +121,17 @@ public class PutAugmentationTest extends AbstractDataServiceTest implements Data
         fnub.setDescription("Description Foo");
         fnub.setSoftware("JUnit emulated");
         FlowCapableNode fnu = fnub.build();
-        InstanceIdentifier<FlowCapableNode> augmentIdentifier = InstanceIdentifier.builder(NODE_INSTANCE_ID_BA).augmentation(FlowCapableNode.class).toInstance();
+        InstanceIdentifier<FlowCapableNode> augmentIdentifier = InstanceIdentifier.builder(NODE_INSTANCE_ID_BA)
+                .augmentation(FlowCapableNode.class).toInstance();
         DataModificationTransaction augmentedTransaction = baDataService.beginTransaction();
         augmentedTransaction.putOperationalData(augmentIdentifier, fnu);
-        
+
         result = augmentedTransaction.commit().get();
         assertEquals(TransactionStatus.COMMITED, result.getResult());
-        
-        
+
+        assertNotNull(lastReceivedChangeEvent);
+        assertTrue(lastReceivedChangeEvent.getCreatedOperationalData().containsKey(FLOW_AUGMENTATION_PATH));
+
         Node augmentedNode = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA);
         assertNotNull(node);
         assertEquals(NODE_KEY, augmentedNode.getKey());
@@ -138,11 +141,14 @@ public class PutAugmentationTest extends AbstractDataServiceTest implements Data
         assertEquals(fnu.getDescription(), readedAugmentation.getDescription());
         assertBindingIndependentVersion(NODE_INSTANCE_ID_BI);
         testNodeRemove();
+        assertTrue(lastReceivedChangeEvent.getRemovedOperationalData().contains(FLOW_AUGMENTATION_PATH));
     }
-    
+
     @Test
     public void putNodeWithAugmentation() throws Exception {
-        
+
+        baDataService.registerDataChangeListener(ALL_FLOW_CAPABLE_NODES, this);
+
         NodeBuilder nodeBuilder = new NodeBuilder();
         nodeBuilder.setId(new NodeId(NODE_ID));
         nodeBuilder.setKey(NODE_KEY);
@@ -153,42 +159,51 @@ public class PutAugmentationTest extends AbstractDataServiceTest implements Data
         fnub.setDescription("Description Foo");
         fnub.setSoftware("JUnit emulated");
         FlowCapableNode fnu = fnub.build();
-        
+
         nodeBuilder.addAugmentation(FlowCapableNode.class, fnu);
         DataModificationTransaction baseTransaction = baDataService.beginTransaction();
         baseTransaction.putOperationalData(NODE_INSTANCE_ID_BA, nodeBuilder.build());
         RpcResult<TransactionStatus> result = baseTransaction.commit().get();
+
+        assertNotNull(lastReceivedChangeEvent);
+        assertTrue(lastReceivedChangeEvent.getCreatedOperationalData().containsKey(FLOW_AUGMENTATION_PATH));
+        lastReceivedChangeEvent = null;
         assertEquals(TransactionStatus.COMMITED, result.getResult());
-        
-        FlowCapableNode readedAugmentation = (FlowCapableNode) baDataService.readOperationalData(InstanceIdentifier.builder(NODE_INSTANCE_ID_BA).augmentation(FlowCapableNode.class).toInstance());
+
+        FlowCapableNode readedAugmentation = (FlowCapableNode) baDataService.readOperationalData(InstanceIdentifier
+                .builder(NODE_INSTANCE_ID_BA).augmentation(FlowCapableNode.class).toInstance());
         assertNotNull(readedAugmentation);
+
         assertEquals(fnu.getHardware(), readedAugmentation.getHardware());
-        
+
         testPutNodeConnectorWithAugmentation();
+        lastReceivedChangeEvent = null;
         testNodeRemove();
+
+        assertTrue(lastReceivedChangeEvent.getRemovedOperationalData().contains(FLOW_AUGMENTATION_PATH));
     }
 
-    
     private void testPutNodeConnectorWithAugmentation() throws Exception {
         NodeConnectorKey ncKey = new NodeConnectorKey(new NodeConnectorId("test:0:0"));
         InstanceIdentifier<NodeConnector> ncPath = InstanceIdentifier.builder(NODE_INSTANCE_ID_BA)
-        .child(NodeConnector.class, ncKey).toInstance();
+                .child(NodeConnector.class, ncKey).toInstance();
         InstanceIdentifier<FlowCapableNodeConnector> ncAugmentPath = InstanceIdentifier.builder(ncPath)
-        .augmentation(FlowCapableNodeConnector.class).toInstance();
-        
+                .augmentation(FlowCapableNodeConnector.class).toInstance();
+
         NodeConnectorBuilder nc = new NodeConnectorBuilder();
         nc.setKey(ncKey);
-        
+
         FlowCapableNodeConnectorBuilder fncb = new FlowCapableNodeConnectorBuilder();
         fncb.setName("Baz");
         nc.addAugmentation(FlowCapableNodeConnector.class, fncb.build());
-        
+
         DataModificationTransaction baseTransaction = baDataService.beginTransaction();
         baseTransaction.putOperationalData(ncPath, nc.build());
         RpcResult<TransactionStatus> result = baseTransaction.commit().get();
         assertEquals(TransactionStatus.COMMITED, result.getResult());
-        
-        FlowCapableNodeConnector readedAugmentation = (FlowCapableNodeConnector) baDataService.readOperationalData(ncAugmentPath);
+
+        FlowCapableNodeConnector readedAugmentation = (FlowCapableNodeConnector) baDataService
+                .readOperationalData(ncAugmentPath);
         assertNotNull(readedAugmentation);
         assertEquals(fncb.getName(), readedAugmentation.getName());
     }
@@ -198,29 +213,28 @@ public class PutAugmentationTest extends AbstractDataServiceTest implements Data
         transaction.removeOperationalData(NODE_INSTANCE_ID_BA);
         RpcResult<TransactionStatus> result = transaction.commit().get();
         assertEquals(TransactionStatus.COMMITED, result.getResult());
-        
+
         Node node = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA);
         assertNull(node);
     }
 
-    private void verifyNodes(Nodes nodes,Node original) {
+    private void verifyNodes(Nodes nodes, Node original) {
         assertNotNull(nodes);
         assertNotNull(nodes.getNode());
         assertEquals(1, nodes.getNode().size());
         Node readedNode = nodes.getNode().get(0);
         assertEquals(original.getId(), readedNode.getId());
         assertEquals(original.getKey(), readedNode.getKey());
-        
+
         FlowCapableNode fnu = original.getAugmentation(FlowCapableNode.class);
         FlowCapableNode readedAugment = readedNode.getAugmentation(FlowCapableNode.class);
         assertNotNull(fnu);
         assertEquals(fnu.getDescription(), readedAugment.getDescription());
         assertEquals(fnu.getSerialNumber(), readedAugment.getSerialNumber());
-        
+
     }
 
-    private void assertBindingIndependentVersion(
-            org.opendaylight.yangtools.yang.data.api.InstanceIdentifier nodeId) {
+    private void assertBindingIndependentVersion(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier nodeId) {
         CompositeNode node = biDataService.readOperationalData(nodeId);
         assertNotNull(node);
     }
@@ -228,10 +242,10 @@ public class PutAugmentationTest extends AbstractDataServiceTest implements Data
     private Nodes checkForNodes() {
         return (Nodes) baDataService.readOperationalData(NODES_INSTANCE_ID_BA);
     }
-    
+
     @Override
     public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
-        receivedChangeEvent = change;
+        lastReceivedChangeEvent = change;
     }
 
 }
index ab86836f95c56dc3212bc77dd7b7365b89dee337..63094ef3cb207ea1a99de3f1024f60b5b0a8781a 100644 (file)
@@ -14,11 +14,8 @@ import java.math.BigInteger;
 import java.util.Collections;
 import java.util.Map;
 
-import javax.management.Notification;
-
 import org.junit.Before;
 import org.junit.Test;
-import org.opendaylight.controller.md.sal.common.api.data.DataModification;
 import org.opendaylight.controller.md.sal.common.api.data.DataReader;
 import org.opendaylight.controller.sal.binding.api.mount.MountProviderInstance;
 import org.opendaylight.controller.sal.binding.api.mount.MountProviderService;
@@ -27,11 +24,8 @@ import org.opendaylight.controller.sal.binding.test.util.BindingTestContext;
 import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
 import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatistics;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.statistics.GroupStatistics;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
@@ -42,14 +36,11 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
-import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
-import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder;
 
-import com.google.common.collect.ImmutableMap;
 import com.google.common.util.concurrent.MoreExecutors;
 
 public class CrossBrokerMountPointTest {
@@ -127,8 +118,8 @@ public class CrossBrokerMountPointTest {
         assertNotNull(bindingMountPoint);
 
         final BigInteger packetCount = BigInteger.valueOf(500L);
-        
-        
+
+
         DataReader<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> simpleReader = new DataReader<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode>() {
 
             @Override
@@ -136,7 +127,7 @@ public class CrossBrokerMountPointTest {
                 return null;
             }
 
-            
+
             @Override
             public CompositeNode readOperationalData(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier arg0) {
                 if (arg0.equals(GROUP_STATISTICS_ID_BI)) {
@@ -153,7 +144,7 @@ public class CrossBrokerMountPointTest {
 
         };
         domMountPoint.registerOperationalReader(NODE_INSTANCE_ID_BI, simpleReader);
-        
+
         GroupStatistics data = (GroupStatistics) bindingMountPoint.readOperationalData(GROUP_STATISTICS_ID_BA);
         assertNotNull(data);
         assertEquals(packetCount,data.getPacketCount().getValue());
index 3c5efa5e3af11a44b73fb2fbec2188ef8e7f1340..4e4416777b8eaed7f48aa1ddbb102a3a2b6c84ec 100644 (file)
@@ -10,8 +10,6 @@ package org.opendaylight.controller.test.sal.binding.it;
 import static org.ops4j.pax.exam.CoreOptions.frameworkProperty;
 import static org.ops4j.pax.exam.CoreOptions.junitBundles;
 import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
-import static org.ops4j.pax.exam.CoreOptions.repository;
-import static org.ops4j.pax.exam.CoreOptions.repositories;
 import static org.ops4j.pax.exam.CoreOptions.systemProperty;
 
 import org.ops4j.pax.exam.Option;
@@ -91,9 +89,9 @@ public class TestHelper {
     public static Option bindingAwareSalBundles() {
         return new DefaultCompositeOption( //
                 mdSalCoreBundles(),
-                
+
                 mavenBundle("org.javassist", "javassist").versionAsInProject(), // //
-                
+
                 mavenBundle(YANGTOOLS, "yang-data-api").versionAsInProject(), // //
                 mavenBundle(YANGTOOLS, "yang-data-impl").versionAsInProject(), // //
                 mavenBundle(YANGTOOLS, "yang-model-api").versionAsInProject(), // //
@@ -109,7 +107,7 @@ public class TestHelper {
                         "binding-generator-spi").versionAsInProject(), //
                 mavenBundle(YANGTOOLS, "binding-generator-impl").versionAsInProject(),
                 mavenBundle(YANGTOOLS + ".thirdparty", "antlr4-runtime-osgi-nohead").versionAsInProject(), // //
-                
+
                 mavenBundle(CONTROLLER, "sal-core-api").versionAsInProject().update(), //
                 mavenBundle(CONTROLLER, "sal-binding-api").versionAsInProject(), // //
                 mavenBundle(CONTROLLER, "sal-binding-config").versionAsInProject(), //
@@ -118,7 +116,7 @@ public class TestHelper {
                 mavenBundle(CONTROLLER, "sal-common-util").versionAsInProject(), // //
 
 
-                
+
                 mavenBundle(CONTROLLER, "sal-broker-impl").versionAsInProject(), // //
                 mavenBundle(CONTROLLER, "sal-core-spi").versionAsInProject().update(), //
 
index cd4f8f158d46316f92a860249d2968874041bfd0..9ac94e7b8904a3148128ca0f01f6b7d6a72fa5d0 100644 (file)
@@ -7,21 +7,26 @@
  */
 package org.opendaylight.controller.test.sal.binding.it;
 
-import static org.ops4j.pax.exam.CoreOptions.*;
-import static org.opendaylight.controller.test.sal.binding.it.TestHelper.*;
-
-import javax.inject.Inject;
-
 import org.junit.runner.RunWith;
 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.ops4j.pax.exam.util.PathUtils;
 import org.osgi.framework.BundleContext;
 
+import javax.inject.Inject;
+
+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;
+
 @RunWith(PaxExam.class)
 public abstract class AbstractTest {
 
@@ -32,7 +37,7 @@ public abstract class AbstractTest {
     public static final String YANGTOOLS_MODELS = "org.opendaylight.yangtools.model";
 
     @Inject
-    @Filter(timeout=60*1000)
+    @Filter(timeout=120*1000)
     BindingAwareBroker broker;
 
     @Inject
index 2aa7493e45bf5efe830fd383994c7c770596d75d..da47b174f14c01400dd556ac95ea8da8d8c8fc22 100644 (file)
@@ -11,7 +11,6 @@ import java.util.Collection;
 import java.util.Collections;
 
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
 import org.opendaylight.yangtools.yang.binding.RpcService;
 
index a55e395c5bf065f53c69dbc4afed81149e36bacc..b23ceaaf15b69c0bed04977b97e3bcefb7eab50a 100644 (file)
@@ -19,7 +19,6 @@ import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
-import org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality;
 import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer;
 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
@@ -38,8 +37,8 @@ import org.opendaylight.yangtools.yang.binding.RpcService;
 
 public class NoficationTest extends AbstractTest {
 
-    private FlowListener listener1 = new FlowListener();
-    private FlowListener listener2 = new FlowListener();
+    private final FlowListener listener1 = new FlowListener();
+    private final FlowListener listener2 = new FlowListener();
 
     private Registration<NotificationListener> listener1Reg;
     private Registration<NotificationListener> listener2Reg;
@@ -53,9 +52,9 @@ public class NoficationTest extends AbstractTest {
     @Test
     public void notificationTest() throws Exception {
         /**
-         * 
+         *
          * The registration of the Provider 1.
-         * 
+         *
          */
         AbstractTestProvider provider1 = new AbstractTestProvider() {
             @Override
@@ -69,10 +68,10 @@ public class NoficationTest extends AbstractTest {
         assertNotNull(notifyProviderService);
 
         /**
-         * 
+         *
          * The registration of the Consumer 1. It retrieves Notification Service
          * from MD-SAL and registers SalFlowListener as notification listener
-         * 
+         *
          */
         BindingAwareConsumer consumer1 = new BindingAwareConsumer() {
             @Override
@@ -97,7 +96,7 @@ public class NoficationTest extends AbstractTest {
 
         /**
          * Check that one notification was delivered and has correct cookie.
-         * 
+         *
          */
         assertEquals(1, listener1.addedFlows.size());
         assertEquals(0, listener1.addedFlows.get(0).getCookie().intValue());
@@ -107,31 +106,31 @@ public class NoficationTest extends AbstractTest {
          * registered as notification listener.
          */
         BindingAwareProvider provider = new BindingAwareProvider() {
-            
+
             @Override
             public void onSessionInitiated(ProviderContext session) {
                 listener2Reg = session.getSALService(NotificationProviderService.class).registerNotificationListener(
                         listener2);
             }
-            
+
             @Override
             public void onSessionInitialized(ConsumerContext session) {
                 // TODO Auto-generated method stub
-                
+
             }
-            
+
             @Override
             public Collection<? extends RpcService> getImplementations() {
                 // TODO Auto-generated method stub
                 return null;
             }
-            
+
             @Override
             public Collection<? extends ProviderFunctionality> getFunctionality() {
                 // TODO Auto-generated method stub
                 return null;
             }
-            
+
         };
 
         // registerConsumer method calls onSessionInitialized method above
@@ -153,19 +152,19 @@ public class NoficationTest extends AbstractTest {
         /**
          * Check that 3 notification was delivered to both listeners (first one
          * received 4 in total, second 3 in total).
-         * 
+         *
          */
         assertEquals(4, listener1.addedFlows.size());
         assertEquals(3, listener2.addedFlows.size());
 
         /**
          * The second listener is closed (unregistered)
-         * 
+         *
          */
         listener2Reg.close();
 
         /**
-         * 
+         *
          * The notification 5 is published
          */
         notifyProviderService.publish(flowAdded(10));
@@ -180,7 +179,7 @@ public class NoficationTest extends AbstractTest {
          * Check that first consumer received 5 notifications in total, second
          * consumer received only three. Last notification was never received by
          * second consumer because its listener was unregistered.
-         * 
+         *
          */
         assertEquals(5, listener1.addedFlows.size());
         assertEquals(3, listener2.addedFlows.size());
@@ -190,7 +189,7 @@ public class NoficationTest extends AbstractTest {
     /**
      * Creates instance of the type FlowAdded. Only cookie value is set. It is
      * used only for testing purpose.
-     * 
+     *
      * @param i
      *            cookie value
      * @return instance of the type FlowAdded
@@ -202,7 +201,7 @@ public class NoficationTest extends AbstractTest {
     }
 
     /**
-     * 
+     *
      * Implements
      * {@link org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowListener
      * SalFlowListener} and contains attributes which keep lists of objects of
@@ -225,7 +224,7 @@ public class NoficationTest extends AbstractTest {
         @Override
         public void onFlowRemoved(FlowRemoved notification) {
             removedFlows.add(notification);
-        }; 
+        };
 
         @Override
         public void onFlowUpdated(FlowUpdated notification) {
@@ -235,20 +234,20 @@ public class NoficationTest extends AbstractTest {
         @Override
         public void onSwitchFlowRemoved(SwitchFlowRemoved notification) {
             // TODO Auto-generated method stub
-            
+
         }
 
         @Override
         public void onNodeErrorNotification(NodeErrorNotification notification) {
             // TODO Auto-generated method stub
-            
+
         }
 
         @Override
         public void onNodeExperimenterErrorNotification(
                 NodeExperimenterErrorNotification notification) {
             // TODO Auto-generated method stub
-            
+
         }
 
     }
index 8c81987301651caf3427ff6f92215ca39d0e6217..befe70376468eef0d9687817268c312638698506 100644 (file)
@@ -15,7 +15,6 @@ import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import java.math.BigInteger;
-import java.util.concurrent.Future;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -26,9 +25,7 @@ import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer;
 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeContext;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
@@ -36,7 +33,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.common.RpcResult;
 
 public class RoutedServiceTest extends AbstractTest {
 
@@ -71,7 +67,7 @@ public class RoutedServiceTest extends AbstractTest {
         /**
          * Register provider 1 with first implementation of SalFlowService -
          * service1
-         * 
+         *
          */
         broker.registerProvider(provider1, getBundleContext());
         assertNotNull("Registration should not be null", firstReg);
@@ -89,7 +85,7 @@ public class RoutedServiceTest extends AbstractTest {
         /**
          * Register provider 2 with first implementation of SalFlowService -
          * service2
-         * 
+         *
          */
         broker.registerProvider(provider2, getBundleContext());
         assertNotNull("Registration should not be null", firstReg);
@@ -117,7 +113,7 @@ public class RoutedServiceTest extends AbstractTest {
         /**
          * Consumer creates addFlow message for node one and sends it to the
          * MD-SAL
-         * 
+         *
          */
         AddFlowInput addFlowFirstMessage = createSampleAddFlow(nodeOne, 1);
         consumerService.addFlow(addFlowFirstMessage);
@@ -125,19 +121,19 @@ public class RoutedServiceTest extends AbstractTest {
         /**
          * Verifies that implementation of the first provider received the same
          * message from MD-SAL.
-         * 
+         *
          */
         verify(salFlowService1).addFlow(addFlowFirstMessage);
 
         /**
          * Verifies that second instance was not invoked with first message
-         * 
+         *
          */
         verify(salFlowService2, times(0)).addFlow(addFlowFirstMessage);
 
         /**
          * Provider 2 registers path of node 2
-         * 
+         *
          */
         NodeRef nodeTwo = createNodeRef("foo:node:2");
         secondReg.registerPath(NodeContext.class, nodeTwo.getValue());
@@ -154,26 +150,26 @@ public class RoutedServiceTest extends AbstractTest {
         /**
          * Verifies that second instance was invoked 3 times with second message
          * and first instance wasn't invoked.
-         * 
+         *
          */
         verify(salFlowService2, times(3)).addFlow(AddFlowSecondMessage);
         verify(salFlowService1, times(0)).addFlow(AddFlowSecondMessage);
 
         /**
          * Unregisteration of the path for the node one in the first provider
-         * 
+         *
          */
         firstReg.unregisterPath(NodeContext.class, nodeOne.getValue());
 
         /**
          * Provider 2 registers path of node 1
-         * 
+         *
          */
         secondReg.registerPath(NodeContext.class, nodeOne.getValue());
 
         /**
          * A consumer sends third message to node 1
-         * 
+         *
          */
         AddFlowInput AddFlowThirdMessage = createSampleAddFlow(nodeOne, 3);
         consumerService.addFlow(AddFlowThirdMessage);
@@ -189,7 +185,7 @@ public class RoutedServiceTest extends AbstractTest {
 
     /**
      * Returns node reference from string which represents path
-     * 
+     *
      * @param string
      *            string with key(path)
      * @return instance of the type NodeRef
@@ -204,7 +200,7 @@ public class RoutedServiceTest extends AbstractTest {
 
     /**
      * Creates flow AddFlowInput for which only node and cookie are set
-     * 
+     *
      * @param node
      *            NodeRef value
      * @param cookie
index 0c562f5d3344f58b1ea9ff9426c5c701632a8502..77b411002b01e480bca055c7507ef59c0915d834 100644 (file)
@@ -8,20 +8,14 @@
 package org.opendaylight.controller.md.sal.binding.util;
 
 import java.util.concurrent.Future;
-import java.util.zip.Checksum;
 
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
 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.RpcProviderRegistry;
 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.binding.api.mount.MountInstance;
 import org.opendaylight.controller.sal.common.DataStoreIdentifier;
-import org.opendaylight.yangtools.concepts.Identifiable;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.concepts.Registration;
 import org.opendaylight.yangtools.yang.binding.DataObject;
@@ -54,7 +48,7 @@ public abstract class AbstractBindingSalConsumerInstance<D extends DataBrokerSer
     protected final D getDataBroker() {
         return dataBroker;
     }
-    
+
     protected final R getRpcRegistryChecked() {
         Preconditions.checkState(rpcRegistry != null,"Rpc Registry is not available.");
         return rpcRegistry;
@@ -69,7 +63,7 @@ public abstract class AbstractBindingSalConsumerInstance<D extends DataBrokerSer
         Preconditions.checkState(dataBroker != null, "Data Broker is not available");
         return dataBroker;
     }
-    
+
 
     protected AbstractBindingSalConsumerInstance(R rpcRegistry, N notificationBroker, D dataBroker) {
         this.rpcRegistry = rpcRegistry;
@@ -77,106 +71,127 @@ public abstract class AbstractBindingSalConsumerInstance<D extends DataBrokerSer
         this.dataBroker = dataBroker;
     }
 
+    @Override
     public <T extends RpcService> T getRpcService(Class<T> module) {
         return getRpcRegistryChecked().getRpcService(module);
     }
 
+    @Override
     @Deprecated
     public <T extends Notification> void addNotificationListener(Class<T> notificationType,
             NotificationListener<T> listener) {
         getNotificationBrokerChecked().addNotificationListener(notificationType, listener);
     }
 
+    @Override
     @Deprecated
     public void addNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) {
         getNotificationBrokerChecked().addNotificationListener(listener);
     }
 
+    @Override
     @Deprecated
     public void removeNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) {
         getNotificationBrokerChecked().removeNotificationListener(listener);
     }
 
+    @Override
     @Deprecated
     public <T extends Notification> void removeNotificationListener(Class<T> notificationType,
             NotificationListener<T> listener) {
         getNotificationBrokerChecked().removeNotificationListener(notificationType, listener);
     }
 
+    @Override
     public <T extends Notification> Registration<NotificationListener<T>> registerNotificationListener(
             Class<T> notificationType, NotificationListener<T> listener) {
         return getNotificationBrokerChecked().registerNotificationListener(notificationType, listener);
     }
 
+    @Override
     public Registration<org.opendaylight.yangtools.yang.binding.NotificationListener> registerNotificationListener(
             org.opendaylight.yangtools.yang.binding.NotificationListener listener) {
         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) {
         return getDataBrokerChecked().readConfigurationData(path);
     }
 
+    @Override
     public DataObject readOperationalData(InstanceIdentifier<? extends DataObject> path) {
         return getDataBrokerChecked().readOperationalData(path);
     }
 
+    @Override
     @Deprecated
     public ListenerRegistration<DataChangeListener> registerDataChangeListener(
             InstanceIdentifier<? extends DataObject> path, DataChangeListener listener) {
index c7d6640ce1eb6c53df124c5338290519f4843e14..efa02e0b301303d9a3444771f15afe4df64d1ec0 100644 (file)
@@ -19,7 +19,6 @@ import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistr
 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
-import org.opendaylight.controller.sal.binding.api.mount.MountProviderInstance;
 import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.concepts.Registration;
@@ -99,7 +98,7 @@ public abstract class AbstractBindingSalProviderInstance<D extends DataProviderS
             L listener) {
         return getRpcRegistryChecked().registerRouteChangeListener(listener);
     }
-    
+
     @Override
     public ListenerRegistration<NotificationInterestListener> registerInterestListener(
             NotificationInterestListener interestListener) {
index d164f82222bb50781ca854b2c5a661791468c1a6..dc22891b471dc2aaa623f096e21395099f0d7328 100644 (file)
@@ -7,26 +7,24 @@
  */
 package org.opendaylight.controller.md.sal.binding.util;
 
-import java.awt.image.SinglePixelPackedSampleModel;
+import static com.google.common.base.Preconditions.checkNotNull;
 
 import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
+import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer;
 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality;
-import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier;
-import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer;
 import org.opendaylight.controller.sal.binding.api.BindingAwareService;
 import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry;
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.RpcService;
 
-import static com.google.common.base.Preconditions.*;
-
 import com.google.common.collect.ClassToInstanceMap;
 import com.google.common.collect.MutableClassToInstanceMap;
 
@@ -38,7 +36,7 @@ public class BindingContextUtils {
         checkNotNull(serviceProvider,"Service map should not be null");
         return new SingleConsumerContextImpl(serviceProvider);
     }
-    
+
     public static ProviderContext createProviderContext(BindingAwareProvider provider,
             ClassToInstanceMap<BindingAwareService> serviceProvider) {
         checkNotNull(provider,"Provider should not be null");
@@ -52,7 +50,7 @@ public class BindingContextUtils {
         consumer.onSessionInitialized(context);
         return context;
     }
-    
+
     public static ProviderContext createProviderContextAndInitialize(BindingAwareProvider provider,
             ClassToInstanceMap<BindingAwareService> serviceProvider) {
         ProviderContext context = createProviderContext(provider, serviceProvider);
@@ -64,9 +62,9 @@ public class BindingContextUtils {
         // FIXME: Create Proxy
         return instance;
     }
-    
+
     private static class SingleConsumerContextImpl implements ConsumerContext, AutoCloseable {
-        
+
         private ClassToInstanceMap<BindingAwareService> alreadyRetrievedServices;
         private ClassToInstanceMap<BindingAwareService> serviceProvider;
 
@@ -79,7 +77,7 @@ public class BindingContextUtils {
         public final <T extends RpcService> T getRpcService(Class<T> module) {
             return getSALService(RpcConsumerRegistry.class).getRpcService(module);
         }
-        
+
         @Override
         public final <T extends BindingAwareService> T getSALService(Class<T> service) {
             checkNotNull(service,"Service class should not be null.");
@@ -89,7 +87,7 @@ public class BindingContextUtils {
             }
             return tryToRetrieveSalService(service);
         }
-        
+
         private synchronized <T extends BindingAwareService> T tryToRetrieveSalService(Class<T> service) {
             final T potential = alreadyRetrievedServices.getInstance(service);
             if(potential != null) {
@@ -103,44 +101,44 @@ public class BindingContextUtils {
             alreadyRetrievedServices.put(service, retrieved);
             return retrieved;
         }
-        
+
         @Override
         public final void close() throws Exception {
             alreadyRetrievedServices = null;
             serviceProvider = null;
         }
     }
-    
+
     private static class SingleProviderContextImpl extends SingleConsumerContextImpl implements ProviderContext {
 
         public SingleProviderContextImpl(ClassToInstanceMap<BindingAwareService> serviceProvider) {
             super(serviceProvider);
         }
-        
+
         @Override
         public <L extends RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>>> ListenerRegistration<L> registerRouteChangeListener(
                 L listener) {
             return getSALService(RpcProviderRegistry.class).registerRouteChangeListener(listener);
         }
-        
+
         @Override
         public <T extends RpcService> RoutedRpcRegistration<T> addRoutedRpcImplementation(Class<T> type,
                 T implementation) throws IllegalStateException {
             return getSALService(RpcProviderRegistry.class).addRoutedRpcImplementation(type, implementation);
         }
-        
+
         @Override
         public <T extends RpcService> RpcRegistration<T> addRpcImplementation(Class<T> type, T implementation)
                 throws IllegalStateException {
             return getSALService(RpcProviderRegistry.class).addRpcImplementation(type, implementation);
         }
-        
+
         @Deprecated
         @Override
         public void registerFunctionality(ProviderFunctionality functionality) {
             // NOOP
         }
-        
+
         @Deprecated
         @Override
         public void unregisterFunctionality(ProviderFunctionality functionality) {
index 92ff55175c4cb5ad948dfebc99d1bd0eacf6e32f..a8989c4ce865616d7515158407d228d922a50196 100644 (file)
@@ -8,9 +8,26 @@
 package org.opendaylight.controller.md.sal.common.api;
 
 public enum TransactionStatus {
+    /**
+     * The transaction has been freshly allocated. The user is still accessing
+     * it and it has not been sealed.
+     */
     NEW,
+    /**
+     * The transaction has been completed by the user and sealed. It is currently
+     * awaiting execution.
+     */
     SUBMITED,
+    /**
+     * The transaction has been successfully committed to backing store.
+     */
     COMMITED,
+    /**
+     * The transaction has failed to commit due to some underlying issue.
+     */
     FAILED,
-    CANCELED
+    /**
+     * Currently unused.
+     */
+    CANCELED,
 }
index 1700411df8072c3f3ca331661323a1aedf971312..66645e5538d6efb0935231100c0a72890ed09a70 100644 (file)
@@ -9,10 +9,9 @@ package org.opendaylight.controller.md.sal.common.api.data;
 
 
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
+
 // FIXME: After 0.6 Release of YANGTools refactor to use Path marker interface for arguments.
 // import org.opendaylight.yangtools.concepts.Path;
-import org.opendaylight.yangtools.concepts.Registration;
-
 public interface DataChangePublisher<P/* extends Path<P> */,D, L extends DataChangeListener<P,D>> {
 
     ListenerRegistration<L> registerDataChangeListener(P path, L listener);
index 29ba192ba821294ceff36aa8de3b83a445edce16..00db6064aa3bb54fa2a1f123be45d67289e63c52 100644 (file)
@@ -7,20 +7,18 @@
  */
 package org.opendaylight.controller.md.sal.common.api.data;
 
-import java.util.Map;
-import java.util.Set;
 import java.util.concurrent.Future;
 
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
-// FIXME: After 0.6 Release of YANGTools refactor to use Path marker interface for arguments.
-// import org.opendaylight.yangtools.concepts.Path;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 
+//FIXME: After 0.6 Release of YANGTools refactor to use Path marker interface for arguments.
+//import org.opendaylight.yangtools.concepts.Path;
 public interface DataModification<P/* extends Path<P> */, D> extends DataChange<P, D>, DataReader<P, D> {
 
     /**
      * Returns transaction identifier
-     * 
+     *
      * @return Transaction identifier
      */
     Object getIdentifier();
@@ -28,9 +26,9 @@ public interface DataModification<P/* extends Path<P> */, D> extends DataChange<
     TransactionStatus getStatus();
 
     /**
-     * 
+     *
      * @deprecated Use {@link #putOperationalData(Object, Object)} instead.
-     * 
+     *
      * @param path
      * @param data
      */
@@ -81,7 +79,7 @@ public interface DataModification<P/* extends Path<P> */, D> extends DataChange<
 
     /**
      * @deprecated Use {@link #removeOperationalData(Object)}
-     * 
+     *
      * @param path
      */
     @Deprecated
@@ -93,18 +91,18 @@ public interface DataModification<P/* extends Path<P> */, D> extends DataChange<
 
     /**
      * Initiates a two-phase commit of modification.
-     * 
+     *
      * <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 Provider components of
      * controller. It is assumed that Consumer has an understanding of this
      * changes.
-     * 
-     * 
+     *
+     *
      * @see DataCommitHandler for further information how two-phase commit is
      *      processed.
      * @param store
index fed75f72bee5229beb26ddc3fe88e257749d8137..f337b5509e1a4cda6d4c1488bef048be5d8adeef 100644 (file)
@@ -7,13 +7,12 @@
  */
 package org.opendaylight.controller.md.sal.common.impl;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 import java.util.Collections;
 import java.util.EventListener;
 import java.util.HashSet;
 import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-import static com.google.common.base.Preconditions.*;
 
 import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
@@ -32,15 +31,15 @@ public class ListenerRegistry<T extends EventListener> {
         return unmodifiableView;
     }
 
-    
+
     public ListenerRegistration<T> register(T listener) {
         checkNotNull(listener, "Listener should not be null.");
         ListenerRegistrationImpl<T> ret = new ListenerRegistrationImpl<T>(listener);
         listeners.add(ret);
         return ret;
     }
-    
-    
+
+
     @SuppressWarnings("rawtypes")
     private void remove(ListenerRegistrationImpl registration) {
         listeners.remove(registration);
index bfa4f36c18ca1d23f852a3da9c554942aa0b3e0e..274f084f01d420cf291723d96949382da5c0cd7d 100644 (file)
@@ -42,7 +42,7 @@ public class RoutingUtils {
         private final Map<C, Set<P>> removal;
         private final Map<C, Set<P>> announcement;
 
-        public RouteChangeImpl(ImmutableMap<C, Set<P>> removal, ImmutableMap<C, Set<P>> announcement) {
+        public RouteChangeImpl(ImmutableMap<C, Set<P>> announcement, ImmutableMap<C, Set<P>> removal) {
             super();
             this.removal = removal;
             this.announcement = announcement;
diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.java
new file mode 100644 (file)
index 0000000..bfffb59
--- /dev/null
@@ -0,0 +1,441 @@
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.common.impl.service;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.eclipse.xtext.xbase.lib.Exceptions;
+import org.opendaylight.controller.md.sal.common.api.RegistrationListener;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.DataChangePublisher;
+import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
+import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration;
+import org.opendaylight.controller.md.sal.common.api.data.DataModificationTransactionFactory;
+import org.opendaylight.controller.md.sal.common.api.data.DataProvisionService;
+import org.opendaylight.controller.md.sal.common.api.data.DataReader;
+import org.opendaylight.controller.md.sal.common.impl.routing.AbstractDataReadRouter;
+import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
+import org.opendaylight.yangtools.concepts.CompositeObjectRegistration;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.Path;
+import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.concepts.util.ListenerRegistry;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
+import com.google.common.util.concurrent.MoreExecutors;
+
+public abstract class AbstractDataBroker<P extends Path<P>, D extends Object, DCL extends DataChangeListener<P, D>>
+        implements DataModificationTransactionFactory<P, D>, DataReader<P, D>, DataChangePublisher<P, D, DCL>,
+        DataProvisionService<P, D> {
+    private final static Logger LOG = LoggerFactory.getLogger(AbstractDataBroker.class);
+
+    private ExecutorService executor;
+
+    public ExecutorService getExecutor() {
+        return this.executor;
+    }
+
+    public void setExecutor(final ExecutorService executor) {
+        this.executor = executor;
+    }
+
+    private ExecutorService notificationExecutor = MoreExecutors.sameThreadExecutor();
+
+    public ExecutorService getNotificationExecutor() {
+        return this.notificationExecutor;
+    }
+
+    public void setNotificationExecutor(final ExecutorService notificationExecutor) {
+        this.notificationExecutor = notificationExecutor;
+    }
+
+    private AbstractDataReadRouter<P, D> dataReadRouter;
+
+    private final AtomicLong submittedTransactionsCount = new AtomicLong();
+
+    private final AtomicLong failedTransactionsCount = new AtomicLong();
+
+    private final AtomicLong finishedTransactionsCount = new AtomicLong();
+
+    public AbstractDataReadRouter<P, D> getDataReadRouter() {
+        return this.dataReadRouter;
+    }
+
+    public void setDataReadRouter(final AbstractDataReadRouter<P, D> dataReadRouter) {
+        this.dataReadRouter = dataReadRouter;
+    }
+
+    public AtomicLong getSubmittedTransactionsCount() {
+        return this.submittedTransactionsCount;
+    }
+
+    public AtomicLong getFailedTransactionsCount() {
+        return this.failedTransactionsCount;
+    }
+
+    public AtomicLong getFinishedTransactionsCount() {
+        return this.finishedTransactionsCount;
+    }
+
+    private final Multimap<P, DataChangeListenerRegistration<P, D, DCL>> listeners = Multimaps
+            .synchronizedSetMultimap(HashMultimap.<P, DataChangeListenerRegistration<P, D, DCL>> create());
+
+    private final Multimap<P, DataCommitHandlerRegistrationImpl<P, D>> commitHandlers = Multimaps
+            .synchronizedSetMultimap(HashMultimap.<P, DataCommitHandlerRegistrationImpl<P, D>> create());
+
+    private final Lock registrationLock = new ReentrantLock();
+
+    private final ListenerRegistry<RegistrationListener<DataCommitHandlerRegistration<P, D>>> commitHandlerRegistrationListeners = new ListenerRegistry<RegistrationListener<DataCommitHandlerRegistration<P, D>>>();
+
+    public AbstractDataBroker() {
+    }
+
+    protected ImmutableList<DataCommitHandler<P, D>> affectedCommitHandlers(final Set<P> paths) {
+        final Callable<ImmutableList<DataCommitHandler<P, D>>> _function = new Callable<ImmutableList<DataCommitHandler<P, D>>>() {
+            @Override
+            public ImmutableList<DataCommitHandler<P, D>> call() throws Exception {
+                Map<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>> _asMap = commitHandlers.asMap();
+                Set<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>> _entrySet = _asMap.entrySet();
+                FluentIterable<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>> _from = FluentIterable
+                        .<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>> from(_entrySet);
+                final Predicate<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>> _function = new Predicate<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>>() {
+                    @Override
+                    public boolean apply(final Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>> it) {
+                        P _key = it.getKey();
+                        boolean _isAffectedBy = isAffectedBy(_key, paths);
+                        return _isAffectedBy;
+                    }
+                };
+                FluentIterable<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>> _filter = _from
+                        .filter(_function);
+                final Function<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>, Collection<DataCommitHandlerRegistrationImpl<P, D>>> _function_1 = new Function<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>, Collection<DataCommitHandlerRegistrationImpl<P, D>>>() {
+                    @Override
+                    public Collection<DataCommitHandlerRegistrationImpl<P, D>> apply(
+                            final Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>> it) {
+                        Collection<DataCommitHandlerRegistrationImpl<P, D>> _value = it.getValue();
+                        return _value;
+                    }
+                };
+                FluentIterable<DataCommitHandlerRegistrationImpl<P, D>> _transformAndConcat = _filter
+                        .<DataCommitHandlerRegistrationImpl<P, D>> transformAndConcat(_function_1);
+                final Function<DataCommitHandlerRegistrationImpl<P, D>, DataCommitHandler<P, D>> _function_2 = new Function<DataCommitHandlerRegistrationImpl<P, D>, DataCommitHandler<P, D>>() {
+                    @Override
+                    public DataCommitHandler<P, D> apply(final DataCommitHandlerRegistrationImpl<P, D> it) {
+                        DataCommitHandler<P, D> _instance = it.getInstance();
+                        return _instance;
+                    }
+                };
+                FluentIterable<DataCommitHandler<P, D>> _transform = _transformAndConcat
+                        .<DataCommitHandler<P, D>> transform(_function_2);
+                return _transform.toList();
+            }
+        };
+        return AbstractDataBroker.<ImmutableList<DataCommitHandler<P, D>>> withLock(this.registrationLock, _function);
+    }
+
+    protected ImmutableList<DataCommitHandler<P, D>> probablyAffectedCommitHandlers(final HashSet<P> paths) {
+        final Callable<ImmutableList<DataCommitHandler<P, D>>> _function = new Callable<ImmutableList<DataCommitHandler<P, D>>>() {
+            @Override
+            public ImmutableList<DataCommitHandler<P, D>> call() throws Exception {
+                Map<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>> _asMap = commitHandlers.asMap();
+                Set<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>> _entrySet = _asMap.entrySet();
+                FluentIterable<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>> _from = FluentIterable
+                        .<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>> from(_entrySet);
+                final Predicate<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>> _function = new Predicate<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>>() {
+                    @Override
+                    public boolean apply(final Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>> it) {
+                        P _key = it.getKey();
+                        boolean _isProbablyAffectedBy = isProbablyAffectedBy(_key, paths);
+                        return _isProbablyAffectedBy;
+                    }
+                };
+                FluentIterable<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>> _filter = _from
+                        .filter(_function);
+                final Function<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>, Collection<DataCommitHandlerRegistrationImpl<P, D>>> _function_1 = new Function<Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>>, Collection<DataCommitHandlerRegistrationImpl<P, D>>>() {
+                    @Override
+                    public Collection<DataCommitHandlerRegistrationImpl<P, D>> apply(
+                            final Entry<P, Collection<DataCommitHandlerRegistrationImpl<P, D>>> it) {
+                        Collection<DataCommitHandlerRegistrationImpl<P, D>> _value = it.getValue();
+                        return _value;
+                    }
+                };
+                FluentIterable<DataCommitHandlerRegistrationImpl<P, D>> _transformAndConcat = _filter
+                        .<DataCommitHandlerRegistrationImpl<P, D>> transformAndConcat(_function_1);
+                final Function<DataCommitHandlerRegistrationImpl<P, D>, DataCommitHandler<P, D>> _function_2 = new Function<DataCommitHandlerRegistrationImpl<P, D>, DataCommitHandler<P, D>>() {
+                    @Override
+                    public DataCommitHandler<P, D> apply(final DataCommitHandlerRegistrationImpl<P, D> it) {
+                        DataCommitHandler<P, D> _instance = it.getInstance();
+                        return _instance;
+                    }
+                };
+                FluentIterable<DataCommitHandler<P, D>> _transform = _transformAndConcat
+                        .<DataCommitHandler<P, D>> transform(_function_2);
+                return _transform.toList();
+            }
+        };
+        return AbstractDataBroker.<ImmutableList<DataCommitHandler<P, D>>> withLock(this.registrationLock, _function);
+    }
+
+    protected Map<P, D> deepGetBySubpath(final Map<P, D> dataSet, final P path) {
+        return Collections.<P, D> emptyMap();
+    }
+
+    @Override
+    public final D readConfigurationData(final P path) {
+        AbstractDataReadRouter<P, D> _dataReadRouter = this.getDataReadRouter();
+        return _dataReadRouter.readConfigurationData(path);
+    }
+
+    @Override
+    public final D readOperationalData(final P path) {
+        AbstractDataReadRouter<P, D> _dataReadRouter = this.getDataReadRouter();
+        return _dataReadRouter.readOperationalData(path);
+    }
+
+    private static <T extends Object> T withLock(final Lock lock, final Callable<T> method) {
+        lock.lock();
+        try {
+            return method.call();
+        } catch (Exception e) {
+            throw Exceptions.sneakyThrow(e);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    @Override
+    public final Registration<DataCommitHandler<P, D>> registerCommitHandler(final P path,
+            final DataCommitHandler<P, D> commitHandler) {
+        synchronized (commitHandler) {
+            final DataCommitHandlerRegistrationImpl<P, D> registration = new DataCommitHandlerRegistrationImpl<P, D>(
+                    path, commitHandler, this);
+            commitHandlers.put(path, registration);
+            LOG.trace("Registering Commit Handler {} for path: {}", commitHandler, path);
+            for (final ListenerRegistration<RegistrationListener<DataCommitHandlerRegistration<P, D>>> listener : commitHandlerRegistrationListeners) {
+                try {
+                    listener.getInstance().onRegister(registration);
+                } catch (Exception e) {
+                    LOG.error("Unexpected exception in listener {} during invoking onRegister", listener.getInstance(),
+                            e);
+                }
+            }
+            return registration;
+        }
+    }
+
+    @Override
+    public final ListenerRegistration<DCL> registerDataChangeListener(final P path, final DCL listener) {
+        synchronized (listeners) {
+            final DataChangeListenerRegistration<P, D, DCL> reg = new DataChangeListenerRegistration<P, D, DCL>(path,
+                    listener, AbstractDataBroker.this);
+            listeners.put(path, reg);
+            final D initialConfig = getDataReadRouter().readConfigurationData(path);
+            final D initialOperational = getDataReadRouter().readOperationalData(path);
+            final DataChangeEvent<P, D> event = createInitialListenerEvent(path, initialConfig, initialOperational);
+            listener.onDataChanged(event);
+            return reg;
+        }
+    }
+
+    public final CompositeObjectRegistration<DataReader<P, D>> registerDataReader(final P path,
+            final DataReader<P, D> reader) {
+
+        final Registration<DataReader<P, D>> confReg = getDataReadRouter().registerConfigurationReader(path, reader);
+        final Registration<DataReader<P, D>> dataReg = getDataReadRouter().registerOperationalReader(path, reader);
+        return new CompositeObjectRegistration<DataReader<P, D>>(reader, Arrays.asList(confReg, dataReg));
+    }
+
+    @Override
+    public ListenerRegistration<RegistrationListener<DataCommitHandlerRegistration<P, D>>> registerCommitHandlerListener(
+            final RegistrationListener<DataCommitHandlerRegistration<P, D>> commitHandlerListener) {
+        final ListenerRegistration<RegistrationListener<DataCommitHandlerRegistration<P, D>>> ret = this.commitHandlerRegistrationListeners
+                .register(commitHandlerListener);
+        return ret;
+    }
+
+    protected DataChangeEvent<P, D> createInitialListenerEvent(final P path, final D initialConfig,
+            final D initialOperational) {
+        InitialDataChangeEventImpl<P, D> _initialDataChangeEventImpl = new InitialDataChangeEventImpl<P, D>(
+                initialConfig, initialOperational);
+        return _initialDataChangeEventImpl;
+    }
+
+    protected final void removeListener(final DataChangeListenerRegistration<P, D, DCL> registration) {
+        synchronized (listeners) {
+            listeners.remove(registration.getPath(), registration);
+        }
+    }
+
+    protected final void removeCommitHandler(final DataCommitHandlerRegistrationImpl<P, D> registration) {
+        synchronized (commitHandlers) {
+
+            commitHandlers.remove(registration.getPath(), registration);
+            LOG.trace("Removing Commit Handler {} for path: {}", registration.getInstance(), registration.getPath());
+            for (final ListenerRegistration<RegistrationListener<DataCommitHandlerRegistration<P, D>>> listener : commitHandlerRegistrationListeners) {
+                try {
+                    listener.getInstance().onUnregister(registration);
+                } catch (Exception e) {
+                    LOG.error("Unexpected exception in listener {} during invoking onUnregister",
+                            listener.getInstance(), e);
+                }
+            }
+        }
+
+    }
+
+    protected final Collection<Entry<P, DataCommitHandlerRegistrationImpl<P, D>>> getActiveCommitHandlers() {
+        return commitHandlers.entries();
+    }
+
+    protected ImmutableList<ListenerStateCapture<P, D, DCL>> affectedListeners(final Set<P> paths) {
+
+        synchronized (listeners) {
+            return FluentIterable //
+                    .from(listeners.asMap().entrySet()) //
+                    .filter(new Predicate<Entry<P, Collection<DataChangeListenerRegistration<P, D, DCL>>>>() {
+                        @Override
+                        public boolean apply(final Entry<P, Collection<DataChangeListenerRegistration<P, D, DCL>>> it) {
+                            return isAffectedBy(it.getKey(), paths);
+                        }
+                    }) //
+                    .transform(
+                            new Function<Entry<P, Collection<DataChangeListenerRegistration<P, D, DCL>>>, ListenerStateCapture<P, D, DCL>>() {
+                                @Override
+                                public ListenerStateCapture<P, D, DCL> apply(
+                                        final Entry<P, Collection<DataChangeListenerRegistration<P, D, DCL>>> it) {
+                                    return new ListenerStateCapture<P, D, DCL>(it.getKey(), it.getValue(),
+                                            createContainsPredicate(it.getKey()));
+                                }
+                            }) //
+                    .toList();
+        }
+    }
+
+    protected ImmutableList<ListenerStateCapture<P, D, DCL>> probablyAffectedListeners(final Set<P> paths) {
+        synchronized (listeners) {
+            return FluentIterable //
+                    .from(listeners.asMap().entrySet()) //
+                    .filter(new Predicate<Entry<P, Collection<DataChangeListenerRegistration<P, D, DCL>>>>() {
+                        @Override
+                        public boolean apply(final Entry<P, Collection<DataChangeListenerRegistration<P, D, DCL>>> it) {
+                            return isProbablyAffectedBy(it.getKey(), paths);
+                        }
+                    }) //
+                    .transform(
+                            new Function<Entry<P, Collection<DataChangeListenerRegistration<P, D, DCL>>>, ListenerStateCapture<P, D, DCL>>() {
+                                @Override
+                                public ListenerStateCapture<P, D, DCL> apply(
+                                        final Entry<P, Collection<DataChangeListenerRegistration<P, D, DCL>>> it) {
+                                    return new ListenerStateCapture<P, D, DCL>(it.getKey(), it.getValue(),
+                                            createIsContainedPredicate(it.getKey()));
+                                }
+                            }) //
+                    .toList();
+        }
+    }
+
+    protected Predicate<P> createContainsPredicate(final P key) {
+        return new Predicate<P>() {
+            @Override
+            public boolean apply(final P other) {
+                return key.contains(other);
+            }
+        };
+    }
+
+    protected Predicate<P> createIsContainedPredicate(final P key) {
+        return new Predicate<P>() {
+            @Override
+            public boolean apply(final P other) {
+                return other.contains(key);
+            }
+        };
+    }
+
+    protected boolean isAffectedBy(final P key, final Set<P> paths) {
+        final Predicate<P> contains = this.createContainsPredicate(key);
+        if (paths.contains(key)) {
+            return true;
+        }
+        for (final P path : paths) {
+            if (contains.apply(path)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    protected boolean isProbablyAffectedBy(final P key, final Set<P> paths) {
+        final Predicate<P> isContained = this.createIsContainedPredicate(key);
+        for (final P path : paths) {
+            if (isContained.apply(path)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    final Future<RpcResult<TransactionStatus>> commit(final AbstractDataTransaction<P, D> transaction) {
+        Preconditions.checkNotNull(transaction);
+        transaction.changeStatus(TransactionStatus.SUBMITED);
+        final TwoPhaseCommit<P, D, DCL> task = new TwoPhaseCommit<P, D, DCL>(transaction, this);
+        ;
+        this.getSubmittedTransactionsCount().getAndIncrement();
+        return this.getExecutor().submit(task);
+    }
+
+    private static class DataCommitHandlerRegistrationImpl<P extends Path<P>, D extends Object> //
+            extends AbstractObjectRegistration<DataCommitHandler<P, D>> //
+            implements DataCommitHandlerRegistration<P, D> {
+
+        private AbstractDataBroker<P, D, ? extends Object> dataBroker;
+        private final P path;
+
+        @Override
+        public P getPath() {
+            return this.path;
+        }
+
+        public DataCommitHandlerRegistrationImpl(final P path, final DataCommitHandler<P, D> instance,
+                final AbstractDataBroker<P, D, ? extends Object> broker) {
+            super(instance);
+            this.dataBroker = broker;
+            this.path = path;
+        }
+
+        @Override
+        protected void removeRegistration() {
+            this.dataBroker.removeCommitHandler(this);
+            this.dataBroker = null;
+        }
+    }
+}
diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend
deleted file mode 100644 (file)
index 2c3b018..0000000
+++ /dev/null
@@ -1,441 +0,0 @@
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.md.sal.common.impl.service\r
-\r
-import com.google.common.collect.FluentIterable\r
-import com.google.common.collect.HashMultimap\r
-import com.google.common.collect.ImmutableList\r
-import com.google.common.collect.Multimap\r
-import java.util.ArrayList\r
-import java.util.Arrays\r
-import java.util.Collection\r
-import java.util.Collections\r
-import java.util.HashSet\r
-import java.util.List\r
-import java.util.Set\r
-import java.util.concurrent.Callable\r
-import java.util.concurrent.ExecutorService\r
-import java.util.concurrent.Future\r
-import java.util.concurrent.atomic.AtomicLong\r
-import org.opendaylight.controller.md.sal.common.api.RegistrationListener\r
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus\r
-import org.opendaylight.controller.md.sal.common.api.data.DataChangeListener\r
-import org.opendaylight.controller.md.sal.common.api.data.DataChangePublisher\r
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler\r
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction\r
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration\r
-import org.opendaylight.controller.md.sal.common.api.data.DataModificationTransactionFactory\r
-import org.opendaylight.controller.md.sal.common.api.data.DataProvisionService\r
-import org.opendaylight.controller.md.sal.common.api.data.DataReader\r
-import org.opendaylight.controller.md.sal.common.impl.AbstractDataModification\r
-import org.opendaylight.controller.md.sal.common.impl.routing.AbstractDataReadRouter\r
-import org.opendaylight.controller.sal.common.util.Rpcs\r
-import org.opendaylight.yangtools.concepts.AbstractObjectRegistration\r
-import org.opendaylight.yangtools.concepts.CompositeObjectRegistration\r
-import org.opendaylight.yangtools.concepts.ListenerRegistration\r
-import org.opendaylight.yangtools.concepts.Path\r
-import org.opendaylight.yangtools.concepts.util.ListenerRegistry\r
-import org.opendaylight.yangtools.yang.common.RpcResult\r
-import org.slf4j.LoggerFactory\r
-\r
-import static com.google.common.base.Preconditions.*\rimport org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent
-import com.google.common.collect.Multimaps
-import java.util.concurrent.locks.Lock
-import java.util.concurrent.locks.ReentrantLock
-
-abstract class AbstractDataBroker<P extends Path<P>, D, DCL extends DataChangeListener<P, D>> implements DataModificationTransactionFactory<P, D>, //\r
-DataReader<P, D>, //\r
-DataChangePublisher<P, D, DCL>, //\r
-DataProvisionService<P, D> {\r
-\r
-    private static val LOG = LoggerFactory.getLogger(AbstractDataBroker);\r
-\r
-    @Property\r
-    var ExecutorService executor;\r
-\r
-    @Property\r
-    var AbstractDataReadRouter<P, D> dataReadRouter;\r
-    \r
-    @Property\r
-    private val AtomicLong submittedTransactionsCount = new AtomicLong;\r
-    \r
-    @Property\r
-    private val AtomicLong failedTransactionsCount = new AtomicLong\r
-    \r
-    @Property\r
-    private val AtomicLong finishedTransactionsCount = new AtomicLong\r
-\r
-    Multimap<P, DataChangeListenerRegistration<P, D, DCL>> listeners = Multimaps.synchronizedSetMultimap(HashMultimap.create());\r
-    Multimap<P, DataCommitHandlerRegistrationImpl<P, D>> commitHandlers = Multimaps.synchronizedSetMultimap(HashMultimap.create());\r
-    
-    private val Lock registrationLock = new ReentrantLock;
-    \r
-    val ListenerRegistry<RegistrationListener<DataCommitHandlerRegistration<P,D>>> commitHandlerRegistrationListeners = new ListenerRegistry();\r
-    public new() {\r
-    }\r
-\r
-    protected def /*Iterator<Entry<Collection<DataChangeListenerRegistration<P,D,DCL>>,D>>*/ affectedCommitHandlers(\r
-        HashSet<P> paths) {
-        return withLock(registrationLock) [|\r
-            return FluentIterable.from(commitHandlers.asMap.entrySet).filter[key.isAffectedBy(paths)] //\r
-                .transformAndConcat[value] //\r
-                .transform[instance].toList()
-        ]\r
-    }\r
-\r
-    override final readConfigurationData(P path) {\r
-        return dataReadRouter.readConfigurationData(path);\r
-    }\r
-\r
-    override final readOperationalData(P path) {\r
-        return dataReadRouter.readOperationalData(path);\r
-    }
-    
-    private static def <T> withLock(Lock lock,Callable<T> method) {
-        lock.lock
-        try {
-            return method.call
-        } finally {
-            lock.unlock
-        }
-    } \r
-\r
-    override final registerCommitHandler(P path, DataCommitHandler<P, D> commitHandler) {
-        return withLock(registrationLock) [|\r
-            val registration = new DataCommitHandlerRegistrationImpl(path, commitHandler, this);\r
-            commitHandlers.put(path, registration)\r
-            LOG.trace("Registering Commit Handler {} for path: {}",commitHandler,path);\r
-            for(listener : commitHandlerRegistrationListeners) {\r
-                try {\r
-                    listener.instance.onRegister(registration);\r
-                } catch (Exception e) {\r
-                    LOG.error("Unexpected exception in listener {} during invoking onRegister",listener.instance,e);\r
-                }\r
-            }
-            return registration;
-        ]\r
-    }\r
-\r
-    override final def registerDataChangeListener(P path, DCL listener) {\r
-        return withLock(registrationLock) [|
-            val reg = new DataChangeListenerRegistration(path, listener, this);\r
-            listeners.put(path, reg);\r
-            val initialConfig = dataReadRouter.readConfigurationData(path);\r
-            val initialOperational = dataReadRouter.readOperationalData(path);\r
-            val event = createInitialListenerEvent(path,initialConfig,initialOperational);\r
-            listener.onDataChanged(event);\r
-            return reg;
-        ]\r
-    }\r
-\r
-    final def registerDataReader(P path, DataReader<P, D> reader) {\r
-        return withLock(registrationLock) [|\r
-            val confReg = dataReadRouter.registerConfigurationReader(path, reader);\r
-            val dataReg = dataReadRouter.registerOperationalReader(path, reader);\r
-    \r
-            return new CompositeObjectRegistration(reader, Arrays.asList(confReg, dataReg));
-        ]\r
-    }\r
-    \r
-    override registerCommitHandlerListener(RegistrationListener<DataCommitHandlerRegistration<P, D>> commitHandlerListener) {\r
-        val ret = commitHandlerRegistrationListeners.register(commitHandlerListener);\r
-        return ret;\r
-    }\r
-    \r
-    protected  def DataChangeEvent<P,D> createInitialListenerEvent(P path,D initialConfig,D initialOperational) {\r
-        return new InitialDataChangeEventImpl<P, D>(initialConfig,initialOperational);\r
-        \r
-    }\r
-\r
-    protected final def removeListener(DataChangeListenerRegistration<P, D, DCL> registration) {
-        return withLock(registrationLock) [|\r
-            listeners.remove(registration.path, registration);
-        ]\r
-    }\r
-\r
-    protected final def removeCommitHandler(DataCommitHandlerRegistrationImpl<P, D> registration) {\r
-        return withLock(registrationLock) [|
-            commitHandlers.remove(registration.path, registration);\r
-             LOG.trace("Removing Commit Handler {} for path: {}",registration.instance,registration.path);\r
-            for(listener : commitHandlerRegistrationListeners) {\r
-                try {\r
-                    listener.instance.onUnregister(registration);\r
-                } catch (Exception e) {\r
-                    LOG.error("Unexpected exception in listener {} during invoking onUnregister",listener.instance,e);\r
-                }\r
-            }
-            return null;
-        ]\r
-    }\r
-\r
-    protected final def getActiveCommitHandlers() {\r
-        return commitHandlers.entries;\r
-    }\r
-\r
-    protected def /*Iterator<Entry<Collection<DataChangeListenerRegistration<P,D,DCL>>,D>>*/ affectedListenersWithInitialState(\r
-        HashSet<P> paths) {
-        return withLock(registrationLock) [|\r
-            return FluentIterable.from(listeners.asMap.entrySet).filter[key.isAffectedBy(paths)].transform [\r
-                val operationalState = readOperationalData(key)\r
-                val configurationState = readConfigurationData(key)\r
-                return new ListenerStateCapture(key, value, operationalState, configurationState)\r
-            ].toList()
-        ]\r
-    }\r
-\r
-    protected def boolean isAffectedBy(P key, Set<P> paths) {\r
-        if (paths.contains(key)) {\r
-            return true;\r
-        }\r
-        for (path : paths) {\r
-            if (key.contains(path)) {\r
-                return true;\r
-            }\r
-        }\r
-\r
-        return false;\r
-    }\r
-\r
-    package final def Future<RpcResult<TransactionStatus>> commit(AbstractDataTransaction<P, D> transaction) {\r
-        checkNotNull(transaction);\r
-        transaction.changeStatus(TransactionStatus.SUBMITED);\r
-        val task = new TwoPhaseCommit(transaction, this);\r
-        submittedTransactionsCount.andIncrement;\r
-        return executor.submit(task);\r
-    }\r
-\r
-}\r
-\r
-@Data\r
-package class ListenerStateCapture<P extends Path<P>, D, DCL extends DataChangeListener<P, D>> {\r
-\r
-    @Property\r
-    P path;\r
-\r
-    @Property\r
-    Collection<DataChangeListenerRegistration<P, D, DCL>> listeners;\r
-\r
-    @Property\r
-    D initialOperationalState;\r
-\r
-    @Property\r
-    D initialConfigurationState;\r
-}\r
-\r
-package class DataChangeListenerRegistration<P extends Path<P>, D, DCL extends DataChangeListener<P, D>> extends AbstractObjectRegistration<DCL> implements ListenerRegistration<DCL> {\r
-\r
-    AbstractDataBroker<P, D, DCL> dataBroker;\r
-\r
-    @Property\r
-    val P path;\r
-\r
-    new(P path, DCL instance, AbstractDataBroker<P, D, DCL> broker) {\r
-        super(instance)\r
-        dataBroker = broker;\r
-        _path = path;\r
-    }\r
-\r
-    override protected removeRegistration() {\r
-        dataBroker.removeListener(this);\r
-        dataBroker = null;\r
-    }\r
-\r
-}\r
-\r
-package class DataCommitHandlerRegistrationImpl<P extends Path<P>, D> //\r
-extends AbstractObjectRegistration<DataCommitHandler<P, D>> //\r
-implements DataCommitHandlerRegistration<P, D> {\r
-\r
-    AbstractDataBroker<P, D, ?> dataBroker;\r
-\r
-    @Property\r
-    val P path;\r
-\r
-    new(P path, DataCommitHandler<P, D> instance, AbstractDataBroker<P, D, ?> broker) {\r
-        super(instance)\r
-        dataBroker = broker;\r
-        _path = path;\r
-    }\r
-\r
-    override protected removeRegistration() {\r
-        dataBroker.removeCommitHandler(this);\r
-        dataBroker = null;\r
-    }\r
-}\r
-\r
-package class TwoPhaseCommit<P extends Path<P>, D, DCL extends DataChangeListener<P, D>> implements Callable<RpcResult<TransactionStatus>> {\r
-\r
-    private static val log = LoggerFactory.getLogger(TwoPhaseCommit);\r
-\r
-    val AbstractDataTransaction<P, D> transaction;\r
-    val AbstractDataBroker<P, D, DCL> dataBroker;\r
-    \r
-    new(AbstractDataTransaction<P, D> transaction, AbstractDataBroker<P, D, DCL> broker) {\r
-        this.transaction = transaction;\r
-        this.dataBroker = broker;\r
-    }\r
-\r
-    override call() throws Exception {\r
-\r
-        // get affected paths\r
-        val affectedPaths = new HashSet<P>();\r
-\r
-        affectedPaths.addAll(transaction.createdConfigurationData.keySet);\r
-        affectedPaths.addAll(transaction.updatedConfigurationData.keySet);\r
-        affectedPaths.addAll(transaction.removedConfigurationData);\r
-\r
-        affectedPaths.addAll(transaction.createdOperationalData.keySet);\r
-        affectedPaths.addAll(transaction.updatedOperationalData.keySet);\r
-        affectedPaths.addAll(transaction.removedOperationalData);\r
-
-        val listeners = dataBroker.affectedListenersWithInitialState(affectedPaths);\r
-\r
-        val transactionId = transaction.identifier;\r
-\r
-        log.trace("Transaction: {} Started.",transactionId);\r
-        log.trace("Transaction: {} Affected Subtrees:",transactionId,affectedPaths);
-        // requesting commits\r
-        val Iterable<DataCommitHandler<P, D>> commitHandlers = dataBroker.affectedCommitHandlers(affectedPaths);\r
-        val List<DataCommitTransaction<P, D>> handlerTransactions = new ArrayList();\r
-        try {\r
-            for (handler : commitHandlers) {\r
-                handlerTransactions.add(handler.requestCommit(transaction));\r
-            }\r
-        } catch (Exception e) {\r
-            log.error("Transaction: {} Request Commit failed", transactionId,e);\r
-            dataBroker.failedTransactionsCount.andIncrement\r
-            transaction.changeStatus(TransactionStatus.FAILED)
-            return rollback(handlerTransactions, e);\r
-        }\r
-        val List<RpcResult<Void>> results = new ArrayList();\r
-        try {\r
-            for (subtransaction : handlerTransactions) {\r
-                results.add(subtransaction.finish());\r
-            }\r
-            listeners.publishDataChangeEvent();\r
-        } catch (Exception e) {\r
-            log.error("Transaction: {} Finish Commit failed",transactionId, e);\r
-            dataBroker.failedTransactionsCount.andIncrement
-            transaction.changeStatus(TransactionStatus.FAILED)\r
-            return rollback(handlerTransactions, e);\r
-        }\r
-        log.trace("Transaction: {} Finished successfully.",transactionId);\r
-        dataBroker.finishedTransactionsCount.andIncrement;
-        transaction.changeStatus(TransactionStatus.COMMITED)\r
-        return Rpcs.getRpcResult(true, TransactionStatus.COMMITED, Collections.emptySet());\r
-\r
-    }\r
-\r
-    def void publishDataChangeEvent(ImmutableList<ListenerStateCapture<P, D, DCL>> listeners) {\r
-        for (listenerSet : listeners) {\r
-            val updatedConfiguration = dataBroker.readConfigurationData(listenerSet.path);\r
-            val updatedOperational = dataBroker.readOperationalData(listenerSet.path);\r
-\r
-            val changeEvent = new DataChangeEventImpl(transaction, listenerSet.initialConfigurationState,\r
-                listenerSet.initialOperationalState, updatedOperational, updatedConfiguration);\r
-            for (listener : listenerSet.listeners) {\r
-                try {\r
-                    listener.instance.onDataChanged(changeEvent);\r
-\r
-                } catch (Exception e) {\r
-                    e.printStackTrace();\r
-                }\r
-            }\r
-        }\r
-    }\r
-\r
-    def rollback(List<DataCommitTransaction<P, D>> transactions, Exception e) {\r
-        for (transaction : transactions) {\r
-            transaction.rollback()\r
-        }\r
-\r
-        // FIXME return encountered error.\r
-        return Rpcs.getRpcResult(false, TransactionStatus.FAILED, Collections.emptySet());\r
-    }\r
-}\r
-\r
-public abstract class AbstractDataTransaction<P extends Path<P>, D> extends AbstractDataModification<P, D> {\r
-\r
-    private static val LOG = LoggerFactory.getLogger(AbstractDataTransaction);
-
-    @Property\r
-    private val Object identifier;\r
-\r
-    var TransactionStatus status;\r
-\r
-    var AbstractDataBroker<P, D, ?> broker;\r
-\r
-    protected new(Object identifier,AbstractDataBroker<P, D, ?> dataBroker) {\r
-        super(dataBroker);\r
-        _identifier = identifier;\r
-        broker = dataBroker;\r
-        status = TransactionStatus.NEW;\r
-        LOG.debug("Transaction {} Allocated.", identifier);
-\r
-    //listeners = new ListenerRegistry<>();\r
-    }\r
-\r
-    override commit() {\r
-        return broker.commit(this);\r
-    }\r
-\r
-    override readConfigurationData(P path) {\r
-        val local = this.updatedConfigurationData.get(path);\r
-        if(local != null) {\r
-            return local;\r
-        }\r
-        \r
-        return broker.readConfigurationData(path);\r
-    }\r
-\r
-    override readOperationalData(P path) {\r
-        val local = this.updatedOperationalData.get(path);\r
-        if(local != null) {\r
-            return local;\r
-        }\r
-        return broker.readOperationalData(path);\r
-    }\r
-\r
-    override hashCode() {\r
-        return identifier.hashCode;\r
-    }\r
-\r
-    override equals(Object obj) {\r
-        if (this === obj)\r
-            return true;\r
-        if (obj == null)\r
-            return false;\r
-        if (getClass() != obj.getClass())\r
-            return false;\r
-        val other = (obj as AbstractDataTransaction<P,D>);\r
-        if (broker == null) {\r
-            if (other.broker != null)\r
-                return false;\r
-        } else if (!broker.equals(other.broker))\r
-            return false;\r
-        if (identifier == null) {\r
-            if (other.identifier != null)\r
-                return false;\r
-        } else if (!identifier.equals(other.identifier))\r
-            return false;\r
-        return true;\r
-    }\r
-\r
-    override TransactionStatus getStatus() {\r
-        return status;\r
-    }\r
-\r
-    protected abstract def void onStatusChange(TransactionStatus status);\r
-\r
-    public def changeStatus(TransactionStatus status) {\r
-        LOG.debug("Transaction {} transitioned from {} to {}", identifier, this.status, status);
-        this.status = status;\r
-        onStatusChange(status);\r
-    }\r
-\r
-}\r
diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataTransaction.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataTransaction.java
new file mode 100644 (file)
index 0000000..c73a627
--- /dev/null
@@ -0,0 +1,108 @@
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.common.impl.service;
+
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.impl.AbstractDataModification;
+import org.opendaylight.yangtools.concepts.Path;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@SuppressWarnings("all")
+public abstract class AbstractDataTransaction<P extends Path<P>, D extends Object> extends
+        AbstractDataModification<P, D> {
+    private final static Logger LOG = LoggerFactory.getLogger(AbstractDataTransaction.class);
+
+    private final Object identifier;
+
+    @Override
+    public Object getIdentifier() {
+        return this.identifier;
+    }
+
+    private TransactionStatus status;
+
+    private final AbstractDataBroker<P, D, ? extends Object> broker;
+
+    protected AbstractDataTransaction(final Object identifier,
+            final AbstractDataBroker<P, D, ? extends Object> dataBroker) {
+        super(dataBroker);
+        this.identifier = identifier;
+        this.broker = dataBroker;
+        this.status = TransactionStatus.NEW;
+        AbstractDataTransaction.LOG.debug("Transaction {} Allocated.", identifier);
+    }
+
+    @Override
+    public Future<RpcResult<TransactionStatus>> commit() {
+        return this.broker.commit(this);
+    }
+
+    @Override
+    public D readConfigurationData(final P path) {
+        final D local = getUpdatedConfigurationData().get(path);
+        if (local != null) {
+            return local;
+        }
+        return this.broker.readConfigurationData(path);
+    }
+
+    @Override
+    public D readOperationalData(final P path) {
+        final D local = this.getUpdatedOperationalData().get(path);
+        if (local != null) {
+            return local;
+        }
+        return this.broker.readOperationalData(path);
+    }
+
+
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((identifier == null) ? 0 : identifier.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        AbstractDataTransaction other = (AbstractDataTransaction) obj;
+        if (identifier == null) {
+            if (other.identifier != null)
+                return false;
+        } else if (!identifier.equals(other.identifier))
+            return false;
+        return true;
+    }
+
+    @Override
+    public TransactionStatus getStatus() {
+        return this.status;
+    }
+
+    protected abstract void onStatusChange(final TransactionStatus status);
+
+    public void changeStatus(final TransactionStatus status) {
+        Object _identifier = this.getIdentifier();
+        AbstractDataTransaction.LOG
+                .debug("Transaction {} transitioned from {} to {}", _identifier, this.status, status);
+        this.status = status;
+        this.onStatusChange(status);
+    }
+}
index 7f5e466c00b56e006538d49cc5803b6277d7490c..691c30368866963abd9137888a17182ce2b6a035 100644 (file)
@@ -20,8 +20,6 @@ public class DataChangeEventImpl<P extends Path<P>, D> implements DataChangeEven
     private final DataChange<P, D> dataChange;
 
     private final D originalConfigurationSubtree;
-
-
     private final D originalOperationalSubtree;
     private final D updatedOperationalSubtree;
     private final D updatedConfigurationSubtree;
diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeListenerRegistration.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeListenerRegistration.java
new file mode 100644 (file)
index 0000000..57d511e
--- /dev/null
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.common.impl.service;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeListener;
+import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.Path;
+
+@SuppressWarnings("all")
+class DataChangeListenerRegistration<P extends Path<P>, D extends Object, DCL extends DataChangeListener<P, D>> extends
+        AbstractObjectRegistration<DCL> implements ListenerRegistration<DCL> {
+    private AbstractDataBroker<P, D, DCL> dataBroker;
+
+    private final P path;
+
+    public P getPath() {
+        return this.path;
+    }
+
+    public DataChangeListenerRegistration(final P path, final DCL instance, final AbstractDataBroker<P, D, DCL> broker) {
+        super(instance);
+        this.dataBroker = broker;
+        this.path = path;
+    }
+
+    @Override
+    protected void removeRegistration() {
+        this.dataBroker.removeListener(this);
+        this.dataBroker = null;
+    }
+}
diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/ImmutableDataChangeEvent.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/ImmutableDataChangeEvent.java
new file mode 100644 (file)
index 0000000..776ff7b
--- /dev/null
@@ -0,0 +1,226 @@
+package org.opendaylight.controller.md.sal.common.impl.service;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.DataModification;
+import org.opendaylight.yangtools.concepts.Path;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+
+final class ImmutableDataChangeEvent<P extends Path<P>, D> implements DataChangeEvent<P,D> {
+
+    private final D updatedOperationalSubtree;
+    private final Map<P, D> updatedOperational;
+    private final D updatedConfigurationSubtree;
+    private final Map<P, D> updatedConfiguration;
+    private final Set<P> removedOperational;
+    private final Set<P> removedConfiguration;
+    private final D originalOperationalSubtree;
+    private final Map<P, D> originalOperational;
+    private final D originalConfigurationSubtree;
+    private final Map<P, D> originalConfiguration;
+    private final Map<P, D> createdOperational;
+    private final Map<P, D> createdConfiguration;
+
+
+    public ImmutableDataChangeEvent(Builder<P, D> builder) {
+
+        createdConfiguration = builder.getCreatedConfiguration().build();
+        createdOperational = builder.getCreatedOperational().build();
+        originalConfiguration = builder.getOriginalConfiguration().build();
+        originalConfigurationSubtree = builder.getOriginalConfigurationSubtree();
+        originalOperational = builder.getOriginalOperational().build();
+        originalOperationalSubtree = builder.getOriginalOperationalSubtree();
+        removedConfiguration = builder.getRemovedConfiguration().build();
+        removedOperational = builder.getRemovedOperational().build();
+        updatedConfiguration = builder.getUpdatedConfiguration().build();
+        updatedConfigurationSubtree = builder.getUpdatedConfigurationSubtree();
+        updatedOperational = builder.getUpdatedOperational().build();
+        updatedOperationalSubtree = builder.getUpdatedOperationalSubtree();
+    }
+
+    @Override
+    public Map<P, D> getCreatedConfigurationData() {
+        return createdConfiguration;
+    }
+
+    @Override
+    public Map<P, D> getCreatedOperationalData() {
+        return createdOperational;
+    }
+
+    @Override
+    public Map<P, D> getOriginalConfigurationData() {
+        return originalConfiguration;
+    }
+    @Override
+    public D getOriginalConfigurationSubtree() {
+        return originalConfigurationSubtree;
+    }
+    @Override
+    public Map<P, D> getOriginalOperationalData() {
+        return originalOperational;
+    }
+    @Override
+    public D getOriginalOperationalSubtree() {
+        return originalOperationalSubtree;
+    }
+    @Override
+    public Set<P> getRemovedConfigurationData() {
+        return removedConfiguration;
+    }
+    @Override
+    public Set<P> getRemovedOperationalData() {
+        return removedOperational;
+    }
+    @Override
+    public Map<P, D> getUpdatedConfigurationData() {
+        return updatedConfiguration;
+    }
+    @Override
+    public D getUpdatedConfigurationSubtree() {
+        return updatedConfigurationSubtree;
+    }
+    @Override
+    public Map<P, D> getUpdatedOperationalData() {
+        return updatedOperational;
+    }
+    @Override
+    public D getUpdatedOperationalSubtree() {
+        return updatedOperationalSubtree;
+    }
+
+    static final <P extends Path<P>,D> Builder<P, D> builder() {
+        return new Builder<>();
+    }
+
+    static final class Builder<P extends Path<P>,D> {
+
+        private  D updatedOperationalSubtree;
+        private  D originalOperationalSubtree;
+        private  D originalConfigurationSubtree;
+        private  D updatedConfigurationSubtree;
+
+        private final ImmutableMap.Builder<P, D> updatedOperational = ImmutableMap.builder();
+        private final ImmutableMap.Builder<P, D> updatedConfiguration = ImmutableMap.builder();
+        private final ImmutableSet.Builder<P> removedOperational = ImmutableSet.builder();
+        private final ImmutableSet.Builder<P> removedConfiguration = ImmutableSet.builder();
+        private final ImmutableMap.Builder<P, D> originalOperational = ImmutableMap.builder();
+
+        private final ImmutableMap.Builder<P, D> originalConfiguration = ImmutableMap.builder();
+        private final ImmutableMap.Builder<P, D> createdOperational = ImmutableMap.builder();
+        private final ImmutableMap.Builder<P, D> createdConfiguration = ImmutableMap.builder();
+
+
+        protected Builder<P,D> addTransaction(DataModification<P, D> data, Predicate<P> keyFilter) {
+            updatedOperational.putAll(Maps.filterKeys(data.getUpdatedOperationalData(), keyFilter));
+            updatedConfiguration.putAll(Maps.filterKeys(data.getUpdatedConfigurationData(), keyFilter));
+            originalConfiguration.putAll(Maps.filterKeys(data.getOriginalConfigurationData(), keyFilter));
+            originalOperational.putAll(Maps.filterKeys(data.getOriginalOperationalData(), keyFilter));
+            createdOperational.putAll(Maps.filterKeys(data.getCreatedOperationalData(), keyFilter));
+            createdConfiguration.putAll(Maps.filterKeys(data.getCreatedConfigurationData(), keyFilter));
+            return this;
+        }
+
+        protected Builder<P, D> addConfigurationChangeSet(RootedChangeSet<P, D> changeSet) {
+            if(changeSet == null) {
+                return this;
+            }
+
+            originalConfiguration.putAll(changeSet.getOriginal());
+            createdConfiguration.putAll(changeSet.getCreated());
+            updatedConfiguration.putAll(changeSet.getUpdated());
+            removedConfiguration.addAll(changeSet.getRemoved());
+            return this;
+        }
+
+        protected Builder<P, D> addOperationalChangeSet(RootedChangeSet<P, D> changeSet) {
+            if(changeSet == null) {
+                return this;
+            }
+            originalOperational.putAll(changeSet.getOriginal());
+            createdOperational.putAll(changeSet.getCreated());
+            updatedOperational.putAll(changeSet.getUpdated());
+            removedOperational.addAll(changeSet.getRemoved());
+            return this;
+        }
+
+        protected ImmutableDataChangeEvent<P, D> build() {
+            return new ImmutableDataChangeEvent<P,D>(this);
+        }
+
+        protected D getUpdatedOperationalSubtree() {
+            return updatedOperationalSubtree;
+        }
+
+        protected Builder<P, D> setUpdatedOperationalSubtree(D updatedOperationalSubtree) {
+            this.updatedOperationalSubtree = updatedOperationalSubtree;
+            return this;
+        }
+
+        protected D getOriginalOperationalSubtree() {
+            return originalOperationalSubtree;
+        }
+
+        protected Builder<P,D> setOriginalOperationalSubtree(D originalOperationalSubtree) {
+            this.originalOperationalSubtree = originalOperationalSubtree;
+            return this;
+        }
+
+        protected D getOriginalConfigurationSubtree() {
+            return originalConfigurationSubtree;
+        }
+
+        protected Builder<P, D> setOriginalConfigurationSubtree(D originalConfigurationSubtree) {
+            this.originalConfigurationSubtree = originalConfigurationSubtree;
+            return this;
+        }
+
+        protected D getUpdatedConfigurationSubtree() {
+            return updatedConfigurationSubtree;
+        }
+
+        protected Builder<P,D> setUpdatedConfigurationSubtree(D updatedConfigurationSubtree) {
+            this.updatedConfigurationSubtree = updatedConfigurationSubtree;
+            return this;
+        }
+
+        protected ImmutableMap.Builder<P, D> getUpdatedOperational() {
+            return updatedOperational;
+        }
+
+        protected ImmutableMap.Builder<P, D> getUpdatedConfiguration() {
+            return updatedConfiguration;
+        }
+
+        protected ImmutableSet.Builder<P> getRemovedOperational() {
+            return removedOperational;
+        }
+
+        protected ImmutableSet.Builder<P> getRemovedConfiguration() {
+            return removedConfiguration;
+        }
+
+        protected ImmutableMap.Builder<P, D> getOriginalOperational() {
+            return originalOperational;
+        }
+
+        protected ImmutableMap.Builder<P, D> getOriginalConfiguration() {
+            return originalConfiguration;
+        }
+
+        protected ImmutableMap.Builder<P, D> getCreatedOperational() {
+            return createdOperational;
+        }
+
+        protected ImmutableMap.Builder<P, D> getCreatedConfiguration() {
+            return createdConfiguration;
+        }
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/ListenerStateCapture.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/ListenerStateCapture.java
new file mode 100644 (file)
index 0000000..502ca90
--- /dev/null
@@ -0,0 +1,118 @@
+package org.opendaylight.controller.md.sal.common.impl.service;
+
+import java.util.Map;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.DataModification;
+import org.opendaylight.yangtools.concepts.Path;
+
+import com.google.common.base.Predicate;
+
+public final class ListenerStateCapture<P extends Path<P>, D, DCL extends DataChangeListener<P, D>> {
+
+    final P path;
+
+    final Iterable<DataChangeListenerRegistration<P, D, DCL>> listeners;
+
+    D initialOperationalState;
+
+    D initialConfigurationState;
+
+    D finalConfigurationState;
+
+    D finalOperationalState;
+
+    Map<P, D> additionalConfigOriginal;
+    Map<P, D> additionalConfigCreated;
+    Map<P, D> additionalConfigUpdated;
+    Map<P, D> additionalConfigDeleted;
+
+    Map<P, D> additionalOperOriginal;
+    Map<P, D> additionalOperCreated;
+    Map<P, D> additionalOperUpdated;
+    Map<P, D> additionalOperDeleted;
+
+    RootedChangeSet<P, D> normalizedConfigurationChanges;
+    RootedChangeSet<P, D> normalizedOperationalChanges;
+
+    private final Predicate<P> containsPredicate;
+
+    public ListenerStateCapture(P path, Iterable<DataChangeListenerRegistration<P, D, DCL>> listeners,
+            Predicate<P> containsPredicate) {
+        super();
+        this.path = path;
+        this.listeners = listeners;
+        this.containsPredicate = containsPredicate;
+    }
+
+    protected D getInitialOperationalState() {
+        return initialOperationalState;
+    }
+
+    protected void setInitialOperationalState(D initialOperationalState) {
+        this.initialOperationalState = initialOperationalState;
+    }
+
+    protected D getInitialConfigurationState() {
+        return initialConfigurationState;
+    }
+
+    protected void setInitialConfigurationState(D initialConfigurationState) {
+        this.initialConfigurationState = initialConfigurationState;
+    }
+
+    protected P getPath() {
+        return path;
+    }
+
+    protected Iterable<DataChangeListenerRegistration<P, D, DCL>> getListeners() {
+        return listeners;
+    }
+
+    protected D getFinalConfigurationState() {
+        return finalConfigurationState;
+    }
+
+    protected void setFinalConfigurationState(D finalConfigurationState) {
+        this.finalConfigurationState = finalConfigurationState;
+    }
+
+    protected D getFinalOperationalState() {
+        return finalOperationalState;
+    }
+
+    protected void setFinalOperationalState(D finalOperationalState) {
+        this.finalOperationalState = finalOperationalState;
+    }
+
+    protected RootedChangeSet<P, D> getNormalizedConfigurationChanges() {
+        return normalizedConfigurationChanges;
+    }
+
+    protected void setNormalizedConfigurationChanges(RootedChangeSet<P, D> normalizedConfigurationChanges) {
+        this.normalizedConfigurationChanges = normalizedConfigurationChanges;
+    }
+
+    protected RootedChangeSet<P, D> getNormalizedOperationalChanges() {
+        return normalizedOperationalChanges;
+    }
+
+    protected void setNormalizedOperationalChanges(RootedChangeSet<P, D> normalizedOperationalChange) {
+        this.normalizedOperationalChanges = normalizedOperationalChange;
+    }
+
+    protected DataChangeEvent<P, D> createEvent(DataModification<P, D> modification) {
+        return ImmutableDataChangeEvent.<P, D> builder()//
+                .addTransaction(modification, containsPredicate) //
+                .addConfigurationChangeSet(normalizedConfigurationChanges) //
+                .addOperationalChangeSet(normalizedOperationalChanges) //
+                .setOriginalConfigurationSubtree(initialConfigurationState) //
+                .setOriginalOperationalSubtree(initialOperationalState) //
+                .setUpdatedConfigurationSubtree(finalConfigurationState) //
+                .setUpdatedOperationalSubtree(finalOperationalState) //
+                .build();
+
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/RootedChangeSet.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/RootedChangeSet.java
new file mode 100644 (file)
index 0000000..e052565
--- /dev/null
@@ -0,0 +1,66 @@
+package org.opendaylight.controller.md.sal.common.impl.service;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.opendaylight.yangtools.concepts.Path;
+
+public class RootedChangeSet<P extends Path<P>,D> {
+
+    private final P root;
+    private final Map<P,D> original;
+    private final Map<P,D> created = new HashMap<>();
+    private final Map<P,D> updated = new HashMap<>();
+    private final Set<P> removed = new HashSet<>();
+
+
+
+    public RootedChangeSet(P root,Map<P, D> original) {
+        super();
+        this.root = root;
+        this.original = original;
+    }
+
+    protected P getRoot() {
+        return root;
+    }
+
+    protected Map<P, D> getOriginal() {
+        return original;
+    }
+
+    protected Map<P, D> getCreated() {
+        return created;
+    }
+
+    protected Map<P, D> getUpdated() {
+        return updated;
+    }
+
+    protected Set<P> getRemoved() {
+        return removed;
+    }
+
+    public void addCreated(Map<P,D> created) {
+        this.created.putAll(created);
+    }
+
+    public void addCreated(Entry<P,D> entry) {
+        created.put(entry.getKey(), entry.getValue());
+    }
+
+    public void addUpdated(Entry<P,D> entry) {
+        updated.put(entry.getKey(), entry.getValue());
+    }
+
+    public void addRemoval(P path) {
+        removed.add(path);
+    }
+
+    public boolean isChange() {
+        return !created.isEmpty() || !updated.isEmpty() || !removed.isEmpty();
+    }
+}
diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/TwoPhaseCommit.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/TwoPhaseCommit.java
new file mode 100644 (file)
index 0000000..e99fc0f
--- /dev/null
@@ -0,0 +1,237 @@
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.common.impl.service;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
+import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction;
+import org.opendaylight.controller.sal.common.util.Rpcs;
+import org.opendaylight.yangtools.concepts.Path;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableList.Builder;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+
+public class TwoPhaseCommit<P extends Path<P>, D extends Object, DCL extends DataChangeListener<P, D>> implements
+        Callable<RpcResult<TransactionStatus>> {
+    private final static Logger log = LoggerFactory.getLogger(TwoPhaseCommit.class);
+
+    private final AbstractDataTransaction<P, D> transaction;
+
+    private final AbstractDataBroker<P, D, DCL> dataBroker;
+
+    public TwoPhaseCommit(final AbstractDataTransaction<P, D> transaction, final AbstractDataBroker<P, D, DCL> broker) {
+        this.transaction = transaction;
+        this.dataBroker = broker;
+    }
+
+    @Override
+    public RpcResult<TransactionStatus> call() throws Exception {
+        final Object transactionId = this.transaction.getIdentifier();
+
+        Set<P> changedPaths = ImmutableSet.<P> builder().addAll(transaction.getUpdatedConfigurationData().keySet())
+                .addAll(transaction.getCreatedConfigurationData().keySet())
+                .addAll(transaction.getRemovedConfigurationData())
+                .addAll(transaction.getUpdatedOperationalData().keySet())
+                .addAll(transaction.getCreatedOperationalData().keySet())
+                .addAll(transaction.getRemovedOperationalData()).build();
+
+        log.trace("Transaction: {} Affected Subtrees:", transactionId, changedPaths);
+
+        final ImmutableList.Builder<ListenerStateCapture<P, D, DCL>> listenersBuilder = ImmutableList.builder();
+        listenersBuilder.addAll(dataBroker.affectedListeners(changedPaths));
+        filterProbablyAffectedListeners(dataBroker.probablyAffectedListeners(changedPaths),listenersBuilder);
+
+
+
+        final ImmutableList<ListenerStateCapture<P, D, DCL>> listeners = listenersBuilder.build();
+        final Iterable<DataCommitHandler<P, D>> commitHandlers = dataBroker.affectedCommitHandlers(changedPaths);
+        captureInitialState(listeners);
+
+
+        log.trace("Transaction: {} Starting Request Commit.",transactionId);
+        final List<DataCommitTransaction<P, D>> handlerTransactions = new ArrayList<>();
+        try {
+            for (final DataCommitHandler<P, D> handler : commitHandlers) {
+                DataCommitTransaction<P, D> requestCommit = handler.requestCommit(this.transaction);
+                if (requestCommit != null) {
+                    handlerTransactions.add(requestCommit);
+                } else {
+                    log.debug("Transaction: {}, Handler {}  is not participating in transaction.", transactionId,
+                            handler);
+                }
+            }
+        } catch (Exception e) {
+            log.error("Transaction: {} Request Commit failed", transactionId, e);
+            dataBroker.getFailedTransactionsCount().getAndIncrement();
+            this.transaction.changeStatus(TransactionStatus.FAILED);
+            return this.rollback(handlerTransactions, e);
+
+        }
+
+        log.trace("Transaction: {} Starting Finish.",transactionId);
+        final List<RpcResult<Void>> results = new ArrayList<RpcResult<Void>>();
+        try {
+            for (final DataCommitTransaction<P, D> subtransaction : handlerTransactions) {
+                results.add(subtransaction.finish());
+            }
+        } catch (Exception e) {
+            log.error("Transaction: {} Finish Commit failed", transactionId, e);
+            dataBroker.getFailedTransactionsCount().getAndIncrement();
+            transaction.changeStatus(TransactionStatus.FAILED);
+            return this.rollback(handlerTransactions, e);
+        }
+
+
+        dataBroker.getFinishedTransactionsCount().getAndIncrement();
+        transaction.changeStatus(TransactionStatus.COMMITED);
+
+        log.trace("Transaction: {} Finished successfully.", transactionId);
+
+        captureFinalState(listeners);
+
+        log.trace("Transaction: {} Notifying listeners.");
+
+        publishDataChangeEvent(listeners);
+        return Rpcs.<TransactionStatus> getRpcResult(true, TransactionStatus.COMMITED,
+                Collections.<RpcError> emptySet());
+    }
+
+    private void captureInitialState(ImmutableList<ListenerStateCapture<P, D, DCL>> listeners) {
+        for (ListenerStateCapture<P, D, DCL> state : listeners) {
+            state.setInitialConfigurationState(dataBroker.readConfigurationData(state.getPath()));
+            state.setInitialOperationalState(dataBroker.readOperationalData(state.getPath()));
+        }
+    }
+
+
+    private void captureFinalState(ImmutableList<ListenerStateCapture<P, D, DCL>> listeners) {
+        for (ListenerStateCapture<P, D, DCL> state : listeners) {
+            state.setFinalConfigurationState(dataBroker.readConfigurationData(state.getPath()));
+            state.setFinalOperationalState(dataBroker.readOperationalData(state.getPath()));
+        }
+    }
+
+    private void filterProbablyAffectedListeners(
+            ImmutableList<ListenerStateCapture<P, D, DCL>> probablyAffectedListeners, Builder<ListenerStateCapture<P, D, DCL>> reallyAffected) {
+
+        for(ListenerStateCapture<P, D, DCL> listenerSet : probablyAffectedListeners) {
+            P affectedPath = listenerSet.getPath();
+            Optional<RootedChangeSet<P,D>> configChange = resolveConfigChange(affectedPath);
+            Optional<RootedChangeSet<P, D>> operChange = resolveOperChange(affectedPath);
+
+            if(configChange.isPresent() || operChange.isPresent()) {
+                reallyAffected.add(listenerSet);
+                if(configChange.isPresent()) {
+                    listenerSet.setNormalizedConfigurationChanges(configChange.get());
+                }
+
+                if(operChange.isPresent()) {
+                    listenerSet.setNormalizedOperationalChanges(operChange.get());
+                }
+            }
+        }
+    }
+
+    private Optional<RootedChangeSet<P, D>> resolveOperChange(P affectedPath) {
+        Map<P, D> originalOper = dataBroker.deepGetBySubpath(transaction.getOriginalOperationalData(),affectedPath);
+        Map<P, D> createdOper = dataBroker.deepGetBySubpath(transaction.getCreatedOperationalData(),affectedPath);
+        Map<P, D> updatedOper = dataBroker.deepGetBySubpath(transaction.getUpdatedOperationalData(),affectedPath);
+        Set<P> removedOper = Sets.filter(transaction.getRemovedOperationalData(), dataBroker.createIsContainedPredicate(affectedPath));
+        return resolveChanges(affectedPath,originalOper,createdOper,updatedOper,removedOper);
+    }
+
+    private Optional<RootedChangeSet<P, D>> resolveConfigChange(P affectedPath) {
+        Map<P, D> originalConfig = dataBroker.deepGetBySubpath(transaction.getOriginalConfigurationData(),affectedPath);
+        Map<P, D> createdConfig = dataBroker.deepGetBySubpath(transaction.getCreatedConfigurationData(),affectedPath);
+        Map<P, D> updatedConfig = dataBroker.deepGetBySubpath(transaction.getUpdatedConfigurationData(),affectedPath);
+        Set<P> removedConfig = Sets.filter(transaction.getRemovedConfigurationData(), dataBroker.createIsContainedPredicate(affectedPath));
+        return resolveChanges(affectedPath,originalConfig,createdConfig,updatedConfig,removedConfig);
+    }
+
+    private Optional<RootedChangeSet<P,D>> resolveChanges(P affectedPath, Map<P, D> originalConfig, Map<P, D> createdConfig, Map<P, D> updatedConfig,Set<P> potentialDeletions) {
+        Predicate<P> isContained = dataBroker.createIsContainedPredicate(affectedPath);
+
+        if(createdConfig.isEmpty() && updatedConfig.isEmpty() && potentialDeletions.isEmpty()) {
+            return Optional.absent();
+        }
+        RootedChangeSet<P, D> changeSet = new RootedChangeSet<P,D>(affectedPath,originalConfig);
+        changeSet.addCreated(createdConfig);
+
+        for(Entry<P, D> entry : updatedConfig.entrySet()) {
+            if(originalConfig.containsKey(entry.getKey())) {
+                changeSet.addUpdated(entry);
+            } else {
+                changeSet.addCreated(entry);
+            }
+        }
+
+        for(Entry<P,D> entry : originalConfig.entrySet()) {
+            for(P deletion : potentialDeletions) {
+                if(isContained.apply(deletion)) {
+                    changeSet.addRemoval(entry.getKey());
+                }
+            }
+        }
+
+        if(changeSet.isChange()) {
+            return Optional.of(changeSet);
+        } else {
+            return Optional.absent();
+        }
+
+    }
+
+    public void publishDataChangeEvent(final ImmutableList<ListenerStateCapture<P, D, DCL>> listeners) {
+        ExecutorService executor = this.dataBroker.getExecutor();
+        final Runnable notifyTask = new Runnable() {
+            @Override
+            public void run() {
+                for (final ListenerStateCapture<P, D, DCL> listenerSet : listeners) {
+                    {
+                        DataChangeEvent<P, D> changeEvent = listenerSet.createEvent(transaction);
+                        for (final DataChangeListenerRegistration<P, D, DCL> listener : listenerSet.getListeners()) {
+                            try {
+                                listener.getInstance().onDataChanged(changeEvent);
+                            } catch (Exception e) {
+                                log.error("Unhandled exception when invoking listener {}", listener);
+                            }
+                        }
+                    }
+                }
+            }
+        };
+        executor.submit(notifyTask);
+    }
+
+    public RpcResult<TransactionStatus> rollback(final List<DataCommitTransaction<P, D>> transactions, final Exception e) {
+        for (final DataCommitTransaction<P, D> transaction : transactions) {
+            transaction.rollback();
+        }
+        Set<RpcError> _emptySet = Collections.<RpcError> emptySet();
+        return Rpcs.<TransactionStatus> getRpcResult(false, TransactionStatus.FAILED, _emptySet);
+    }
+}
index bd9748d3c57814184a6adf36f03102c6bbde56af..4d756f1d67380851c726a41a321a1e53ff7c8993 100644 (file)
@@ -8,8 +8,6 @@
 package org.opendaylight.controller.md.sal.common.impl.util;
 
 import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
@@ -23,8 +21,8 @@ public class AbstractLockableDelegator<T> implements Delegator<T> {
     private final ReentrantReadWriteLock delegateLock = new ReentrantReadWriteLock();
     private final ReadLock delegateReadLock = delegateLock.readLock();
     private final WriteLock delegateWriteLock = delegateLock.writeLock();
-    
-    
+
+
     protected Lock getDelegateReadLock() {
         return delegateReadLock;
     }
@@ -60,7 +58,7 @@ public class AbstractLockableDelegator<T> implements Delegator<T> {
     }
 
     /**
-     * 
+     *
      * @param newDelegate
      * @return oldDelegate
      */
@@ -75,8 +73,8 @@ public class AbstractLockableDelegator<T> implements Delegator<T> {
             delegateWriteLock.unlock();
         }
     }
-    
-    
+
+
     protected void onDelegateChanged(T oldDelegate, T newDelegate) {
         // NOOP in abstract calss;
     }
index 356ec8ff7c5ee6e84692970d702910b7bdc8c091..f30394187125153004e9b5c3a1b4d4cb2cc74886 100644 (file)
@@ -8,9 +8,7 @@
 package org.opendaylight.controller.sal.common.util;
 
 import java.io.Serializable;
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 
 import org.opendaylight.yangtools.concepts.Immutable;
 import org.opendaylight.yangtools.yang.common.RpcError;
@@ -19,12 +17,12 @@ import org.opendaylight.yangtools.yang.common.RpcResult;
 import com.google.common.collect.ImmutableList;
 
 public class Rpcs {
-    
+
     public static <T> RpcResult<T> getRpcResult(boolean successful) {
         RpcResult<T> ret = new RpcResultTO<T>(successful, null, ImmutableList.<RpcError>of());
         return ret;
     }
-    
+
     public static <T> RpcResult<T> getRpcResult(boolean successful, T result,
             Collection<RpcError> errors) {
         RpcResult<T> ret = new RpcResultTO<T>(successful, result, errors);
@@ -34,9 +32,9 @@ public class Rpcs {
     public static <T> RpcResult<T> getRpcResult(boolean successful, Collection<RpcError> errors) {
         return new RpcResultTO<T>(successful, null, errors);
     }
-    
-    private static class RpcResultTO<T> implements RpcResult<T>, Serializable, Immutable {
 
+    private static class RpcResultTO<T> implements RpcResult<T>, Serializable, Immutable {
+        private static final long serialVersionUID = 1L;
         private final Collection<RpcError> errors;
         private final T result;
         private final boolean successful;
index 1cb1a2bc8522b65301e3f70470e2c41e06d3b32c..22b0bf25cf9b65958131ace905b0176d351f4147 100644 (file)
@@ -10,9 +10,6 @@ package org.opendaylight.controller.sal.core.api;
 import java.util.Collection;
 import java.util.Collections;
 
-import javax.naming.Context;
-
-import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
@@ -59,18 +56,18 @@ public abstract class AbstractProvider implements BundleActivator, Provider,Serv
             broker.registerProvider(this, context);
             return broker;
         }
-        
+
         return null;
     }
-    
+
     @Override
     public void modifiedService(ServiceReference<Broker> reference, Broker service) {
         // NOOP
     }
-    
+
     @Override
     public void removedService(ServiceReference<Broker> reference, Broker service) {
         stopImpl(context);
     }
-    
+
 }
index 24cb99f8c367cd566c576f877cb6bcb20b6519e9..8a9d1678657c6b3555ba23d4a3c536cae5d3d30d 100644 (file)
@@ -14,7 +14,7 @@ import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 
-public interface RpcProvisionRegistry extends BrokerService, RouteChangePublisher<RpcRoutingContext, InstanceIdentifier> {
+public interface RpcProvisionRegistry extends RpcImplementation, BrokerService, RouteChangePublisher<RpcRoutingContext, InstanceIdentifier> {
 
     /**
      * Registers an implementation of the rpc.
index 774de271af32878a8b8d3e6dc70070c6a300f308..9706bbacdbdbee3b22c3a8b163b069617b452347 100644 (file)
@@ -8,8 +8,6 @@
 package org.opendaylight.controller.sal.core.api.data;
 
 import java.util.EventListener;
-import java.util.Map;
-import java.util.Set;
 import java.util.concurrent.Future;
 
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
@@ -23,31 +21,28 @@ public interface DataModificationTransaction extends DataModification<InstanceId
 
     /**
      * Returns transaction identifier
-     * 
+     *
      * @return Transaction identifier
      */
+    @Override
     Object getIdentifier();
-    
+
+    @Override
     TransactionStatus getStatus();
-    
+
     /**
      * Commits transaction to be stored in global data repository.
-     * 
-     * 
-     * @return  Future object which returns RpcResult with TransactionStatus 
+     *
+     *
+     * @return  Future object which returns RpcResult with TransactionStatus
      *          when transaction is processed by store.
      */
+    @Override
     Future<RpcResult<TransactionStatus>> commit();
-    
+
     ListenerRegistration<DataTransactionListener> registerListener(DataTransactionListener listener);
-    
-    
+
     public interface DataTransactionListener extends EventListener {
-        
         void onStatusUpdated(DataModificationTransaction transaction,TransactionStatus status);
-        
     }
-    
-    
-    
 }
index 299fe1b55811495adee6c66d880cb7badc063152..29e3b911c1d1b1d8a5cdf64b30da0842bff7d11f 100644 (file)
@@ -10,7 +10,6 @@ package org.opendaylight.controller.sal.core.api.mount;
 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
 import org.opendaylight.controller.sal.core.api.data.DataProviderService;
 import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService;
-import com.google.common.base.Optional;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
 public interface MountProvisionInstance extends //
index 8b193e03aa4620bcbfe1b98602488b53a49d84b9..8553d9eea5d9c9259f7ff55f638871b4be4e6b46 100644 (file)
@@ -64,6 +64,7 @@
 
     <build>
         <plugins>
+            <!-- TODO - unite yang-maven-plugin configuration in md-sal-->
             <plugin>
                 <groupId>org.opendaylight.yangtools</groupId>
                 <artifactId>yang-maven-plugin</artifactId>
index aa5138a04db226d777c70dbd8ece6d3df5b77736..8f734d7d4c3934a22c1ca91af146534a0a5fac5b 100644 (file)
@@ -73,7 +73,7 @@ public class BrokerImpl implements Broker, RpcProvisionRegistry, AutoCloseable {
         return session;
     }
 
-    protected def Future<RpcResult<CompositeNode>> invokeRpc(QName rpc, CompositeNode input) {
+    protected def Future<RpcResult<CompositeNode>> invokeRpcAsync(QName rpc, CompositeNode input) {
         val result = executor.submit([|router.invokeRpc(rpc, input)] as Callable<RpcResult<CompositeNode>>);
         return result;
     }
@@ -135,5 +135,13 @@ public class BrokerImpl implements Broker, RpcProvisionRegistry, AutoCloseable {
     override <L extends RouteChangeListener<RpcRoutingContext, InstanceIdentifier>> registerRouteChangeListener(L listener) {
         return router.registerRouteChangeListener(listener);
     }
+
+    override invokeRpc(QName rpc,CompositeNode input){
+        return router.invokeRpc(rpc,input)
+    }
+
+    override getSupportedRpcs() {
+        return router.getSupportedRpcs();
+    }
     
 }
index e4808e9bd6ddfdc86dace504e67f8173eb1e8ca9..813f52b67d4bab0632fdefb6a9fe7d23d8054792 100644 (file)
@@ -37,7 +37,7 @@ class ConsumerContextImpl implements ConsumerSession {
     }
 
     override rpc(QName rpc, CompositeNode input) {
-        return broker.invokeRpc(rpc, input);
+        return broker.invokeRpcAsync(rpc, input);
     }
 
     override <T extends BrokerService> T getService(Class<T> service) {
index 5a3e060a3c9a52a2c55b4876b283ec5559de63e5..a8bdddb5108d3ab0242024b7c3db4df3a1d1694a 100644 (file)
@@ -219,4 +219,6 @@ public class MountPointImpl implements MountProvisionInstance, SchemaContextProv
             L listener) {
         return rpcs.registerRouteChangeListener(listener);
     }
+
+
 }
index 403f7c8da0e99cdcc0c21aa841849701bc478edf..bbe017f009e445f2ab7e21e7d19b748d3f5365f0 100644 (file)
@@ -9,14 +9,13 @@ package org.opendaylight.controller.sal.dom.broker;
 
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashSet;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 
-import org.opendaylight.controller.sal.core.api.BrokerService;
 import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.controller.sal.core.api.BrokerService;
 import org.opendaylight.controller.sal.core.api.Consumer.ConsumerFunctionality;
 import org.opendaylight.controller.sal.core.api.Provider.ProviderFunctionality;
 import org.opendaylight.controller.sal.core.api.notify.NotificationListener;
@@ -37,7 +36,7 @@ public class NotificationModule implements BrokerModule {
     private static Logger log = LoggerFactory
             .getLogger(NotificationModule.class);
 
-    private Multimap<QName, NotificationListener> listeners = HashMultimap
+    private final Multimap<QName, NotificationListener> listeners = HashMultimap
             .create();
 
     private static final Set<Class<? extends BrokerService>> PROVIDED_SERVICE_TYPE = ImmutableSet
@@ -114,11 +113,12 @@ public class NotificationModule implements BrokerModule {
     private class NotificationConsumerSessionImpl implements
             NotificationService {
 
-        private Multimap<QName, NotificationListener> consumerListeners = HashMultimap
+        private final Multimap<QName, NotificationListener> consumerListeners = HashMultimap
                 .create();
         private boolean closed = false;
 
 
+        @Override
         public Registration<NotificationListener> addNotificationListener(QName notification,
                 NotificationListener listener) {
             checkSessionState();
index 0b184fc86ec0720193210bd8b0a997235caddca8..50af3fbfc1f097662ae4f0a8f1e1084cb87aab96 100644 (file)
@@ -8,21 +8,8 @@
 package org.opendaylight.controller.sal.dom.broker.impl;
 
 import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
 
-import org.opendaylight.controller.sal.core.api.BrokerService;
-import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
-import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
-import org.opendaylight.controller.sal.core.api.Consumer.ConsumerFunctionality;
-import org.opendaylight.controller.sal.core.api.Provider.ProviderFunctionality;
 import org.opendaylight.controller.sal.core.api.notify.NotificationListener;
-import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService;
-import org.opendaylight.controller.sal.core.api.notify.NotificationService;
-import org.opendaylight.controller.sal.core.spi.BrokerModule;
 import org.opendaylight.controller.sal.dom.broker.spi.NotificationRouter;
 import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
 import org.opendaylight.yangtools.concepts.Registration;
@@ -32,16 +19,15 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.collect.HashMultimap;
-import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Multimap;
 import com.google.common.collect.Multimaps;
 
 public class NotificationRouterImpl implements NotificationRouter {
     private static Logger log = LoggerFactory.getLogger(NotificationRouterImpl.class);
 
-    private Multimap<QName, Registration<NotificationListener>> listeners = Multimaps.synchronizedSetMultimap(HashMultimap.<QName, Registration<NotificationListener>>create());
+    private final Multimap<QName, Registration<NotificationListener>> listeners = Multimaps.synchronizedSetMultimap(HashMultimap.<QName, Registration<NotificationListener>>create());
 //    private Registration<NotificationListener> defaultListener;
-    
+
     private void sendNotification(CompositeNode notification) {
         final QName type = notification.getNodeType();
         final Collection<Registration<NotificationListener>> toNotify = listeners.get(type);
@@ -66,7 +52,7 @@ public class NotificationRouterImpl implements NotificationRouter {
     public void publish(CompositeNode notification) {
         sendNotification(notification);
     }
-    
+
     @Override
     public Registration<NotificationListener> addNotificationListener(QName notification, NotificationListener listener) {
         ListenerRegistration ret = new ListenerRegistration(notification, listener);
index 3e6a8252b7b0404a352a1c128cbe17770fc112ab..b02a37c3003e594b728554f6c5a0124961872ce3 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.controller.sal.dom.broker.impl;
 
+import static com.google.common.base.Preconditions.checkState;
+
 import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.Map.Entry;
@@ -18,8 +20,8 @@ import org.opendaylight.controller.md.sal.common.api.data.DataReader;
 import org.opendaylight.controller.md.sal.common.impl.AbstractDataModification;
 import org.opendaylight.controller.md.sal.common.impl.util.AbstractLockableDelegator;
 import org.opendaylight.controller.sal.core.api.data.DataStore;
+import org.opendaylight.controller.sal.dom.broker.util.YangDataOperations;
 import org.opendaylight.controller.sal.dom.broker.util.YangSchemaUtils;
-import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
@@ -28,25 +30,26 @@ import org.opendaylight.yangtools.yang.data.api.Node;
 import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.controller.sal.dom.broker.util.YangDataOperations;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
+import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Predicate;
 import com.google.common.collect.FluentIterable;
-
-import static com.google.common.base.Preconditions.*;
+import com.google.common.collect.ImmutableSet;
 
 public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator<DataStore> implements //
         DataStore, //
         SchemaServiceListener, //
+        SchemaContextListener, //
         AutoCloseable {
 
     private final static Logger LOG = LoggerFactory.getLogger(SchemaAwareDataStoreAdapter.class);
 
     private SchemaContext schema = null;
     private boolean validationEnabled = false;
-    private DataReader<InstanceIdentifier, CompositeNode> reader = new MergeFirstLevelReader();
+    private final DataReader<InstanceIdentifier, CompositeNode> reader = new MergeFirstLevelReader();
 
     @Override
     public boolean containsConfigurationPath(InstanceIdentifier path) {
@@ -164,7 +167,6 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator<DataS
 
     private NormalizedDataModification prepareMergedTransaction(
             DataModification<InstanceIdentifier, CompositeNode> original) {
-        // NOOP for now
         NormalizedDataModification normalized = new NormalizedDataModification(original);
         for (Entry<InstanceIdentifier, CompositeNode> entry : original.getUpdatedConfigurationData().entrySet()) {
             normalized.putConfigurationData(entry.getKey(), entry.getValue());
@@ -173,14 +175,40 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator<DataS
             normalized.putOperationalData(entry.getKey(), entry.getValue());
         }
         for (InstanceIdentifier entry : original.getRemovedConfigurationData()) {
-            normalized.removeConfigurationData(entry);
+            normalized.deepRemoveConfigurationData(entry);
         }
         for (InstanceIdentifier entry : original.getRemovedOperationalData()) {
-            normalized.removeOperationalData(entry);
+            normalized.deepRemoveOperationalData(entry);
         }
         return normalized;
     }
 
+    private Iterable<InstanceIdentifier> getConfigurationSubpaths(InstanceIdentifier entry) {
+        // FIXME: This should be replaced by index
+        Iterable<InstanceIdentifier> paths = getStoredConfigurationPaths();
+
+        return getChildrenPaths(entry, paths);
+
+    }
+
+    public Iterable<InstanceIdentifier> getOperationalSubpaths(InstanceIdentifier entry) {
+        // FIXME: This should be indexed
+        Iterable<InstanceIdentifier> paths = getStoredOperationalPaths();
+
+        return getChildrenPaths(entry, paths);
+    }
+
+    private static final Iterable<InstanceIdentifier> getChildrenPaths(InstanceIdentifier entry,
+            Iterable<InstanceIdentifier> paths) {
+        ImmutableSet.Builder<InstanceIdentifier> children = ImmutableSet.builder();
+        for (InstanceIdentifier potential : paths) {
+            if (entry.contains(potential)) {
+                children.add(entry);
+            }
+        }
+        return children.build();
+    }
+
     private final Comparator<Entry<InstanceIdentifier, CompositeNode>> preparationComparator = new Comparator<Entry<InstanceIdentifier, CompositeNode>>() {
         @Override
         public int compare(Entry<InstanceIdentifier, CompositeNode> o1, Entry<InstanceIdentifier, CompositeNode> o2) {
@@ -282,7 +310,7 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator<DataS
 
     private class NormalizedDataModification extends AbstractDataModification<InstanceIdentifier, CompositeNode> {
 
-        private Object identifier;
+        private final Object identifier;
         private TransactionStatus status;
 
         public NormalizedDataModification(DataModification<InstanceIdentifier, CompositeNode> original) {
@@ -291,6 +319,29 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator<DataS
             status = TransactionStatus.NEW;
         }
 
+        /**
+         *
+         * Ensures all subpaths are removed - this currently does slow lookup in
+         * all keys.
+         *
+         * @param entry
+         */
+        public void deepRemoveOperationalData(InstanceIdentifier entry) {
+            Iterable<InstanceIdentifier> paths = getOperationalSubpaths(entry);
+            removeOperationalData(entry);
+            for (InstanceIdentifier potential : paths) {
+                removeOperationalData(potential);
+            }
+        }
+
+        public void deepRemoveConfigurationData(InstanceIdentifier entry) {
+            Iterable<InstanceIdentifier> paths = getConfigurationSubpaths(entry);
+            removeConfigurationData(entry);
+            for (InstanceIdentifier potential : paths) {
+                removeConfigurationData(potential);
+            }
+        }
+
         @Override
         public Object getIdentifier() {
             return this.identifier;
index 0e63126bb36f3efbfcb7d02c5f59e694aa944bbf..24d5430d6d3713a0c6b3e5a5252eb710e9550e7d 100644 (file)
@@ -7,7 +7,6 @@
  */
 package org.opendaylight.controller.sal.dom.broker.osgi;
 
-import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
 import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
 import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
@@ -16,23 +15,26 @@ import org.osgi.framework.ServiceReference;
 
 public class MountProviderServiceProxy extends AbstractBrokerServiceProxy<MountProvisionService> implements MountProvisionService{
 
-    
+
     public MountProviderServiceProxy(ServiceReference<MountProvisionService> ref, MountProvisionService delegate) {
         super(ref, delegate);
     }
 
+    @Override
     public MountProvisionInstance getMountPoint(InstanceIdentifier path) {
         return getDelegate().getMountPoint(path);
     }
 
+    @Override
     public MountProvisionInstance createMountPoint(InstanceIdentifier path) {
         return getDelegate().createMountPoint(path);
     }
 
+    @Override
     public MountProvisionInstance createOrGetMountPoint(InstanceIdentifier path) {
         return getDelegate().createOrGetMountPoint(path);
     }
-    
+
     @Override
     public ListenerRegistration<MountProvisionListener> registerProvisionListener(MountProvisionListener listener) {
         return getDelegate().registerProvisionListener(listener);
index e375e14cf2e96bf9e4ca29998a156df402ec3420..e218a957826f110bd36d3acb3fe059fc69b5092a 100644 (file)
@@ -16,9 +16,13 @@ import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
 import org.opendaylight.controller.sal.core.api.RpcRoutingContext;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 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.ServiceReference;
 
+import java.util.Set;
+
 public class RpcProvisionRegistryProxy extends AbstractBrokerServiceProxy<RpcProvisionRegistry>
                                        implements RpcProvisionRegistry {
 
@@ -45,4 +49,15 @@ public class RpcProvisionRegistryProxy extends AbstractBrokerServiceProxy<RpcPro
     public <L extends RouteChangeListener<RpcRoutingContext, InstanceIdentifier>> ListenerRegistration<L> registerRouteChangeListener(L listener) {
         return getDelegate().registerRouteChangeListener(listener);
     }
+
+
+  @Override
+  public Set<QName> getSupportedRpcs() {
+    return getDelegate().getSupportedRpcs();
+  }
+
+  @Override
+  public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input) {
+    return getDelegate().invokeRpc(rpc,input);
+  }
 }
index 9881be0481cf016a8b48259ef3719effea75f3a3..d1523a01d695f2033ee9bfa557b1aaf0ea4c592d 100644 (file)
@@ -9,12 +9,10 @@ package org.opendaylight.controller.sal.dom.broker.spi;
 
 import java.util.Set;
 
-import org.opendaylight.controller.sal.core.api.RpcImplementation;
-import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
 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.RpcRegistrationListener;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
@@ -23,14 +21,14 @@ public interface RpcRouter extends RpcProvisionRegistry, RpcImplementation {
 
     @Override
     public RoutedRpcRegistration addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation);
-    
+
     @Override
     public RpcRegistration addRpcImplementation(QName rpcType, RpcImplementation implementation)
             throws IllegalArgumentException;
-    
+
     @Override
     public Set<QName> getSupportedRpcs();
-    
+
     @Override
     public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input);
 }
index a04baaa91298ccf218c74958d76596c89545b204..ddaf6ea6c378ae7728a00cff8297c82650b3a8d9 100644 (file)
@@ -7,9 +7,18 @@
  */
 package org.opendaylight.controller.config.yang.md.sal.connector.netconf;
 
-import com.google.common.net.InetAddresses;
+import static org.opendaylight.controller.config.api.JmxAttributeValidationException.checkCondition;
+import static org.opendaylight.controller.config.api.JmxAttributeValidationException.checkNotNull;
 import io.netty.channel.EventLoopGroup;
 import io.netty.util.concurrent.GlobalEventExecutor;
+
+import java.io.File;
+import java.io.InputStream;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
 import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
 import org.opendaylight.controller.netconf.client.NetconfSshClientDispatcher;
 import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler;
@@ -25,19 +34,11 @@ import org.osgi.framework.BundleContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.File;
-import java.io.InputStream;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-import static org.opendaylight.controller.config.api.JmxAttributeValidationException.checkCondition;
-import static org.opendaylight.controller.config.api.JmxAttributeValidationException.checkNotNull;
+import com.google.common.net.InetAddresses;
 
 /**
-*
-*/
+ *
+ */
 public final class NetconfConnectorModule extends org.opendaylight.controller.config.yang.md.sal.connector.netconf.AbstractNetconfConnectorModule
 {
     private static final Logger logger = LoggerFactory.getLogger(NetconfConnectorModule.class);
@@ -72,7 +73,7 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co
 
     @Override
     public java.lang.AutoCloseable createInstance() {
-        
+
         getDomRegistryDependency();
         NetconfDevice device = new NetconfDevice(getIdentifier().getInstanceName());
         String addressValue = getAddress();
@@ -92,27 +93,27 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co
         } else {
             addressValue = getAddress().getIpv6Address().getValue();
         }
-        */
+         */
         double sleepFactor = 1.0;
         int minSleep = 1000;
         Long maxSleep = null;
         Long deadline = null;
         ReconnectStrategy strategy = new TimedReconnectStrategy(GlobalEventExecutor.INSTANCE, getBetweenAttemptsTimeoutMillis(),
                 minSleep, sleepFactor, maxSleep, connectionAttempts, deadline);
-        
+
         device.setReconnectStrategy(strategy);
-        
+
         InetAddress addr = InetAddresses.forString(addressValue);
         InetSocketAddress socketAddress = new InetSocketAddress(addr , getPort().intValue());
 
-        
+
         device.setProcessingExecutor(getGlobalProcessingExecutor());
-        
+
         device.setSocketAddress(socketAddress);
         device.setEventExecutor(getEventExecutorDependency());
         device.setDispatcher(createDispatcher(clientConnectionTimeoutMillis));
         device.setSchemaSourceProvider(getGlobalNetconfSchemaProvider(bundleContext));
-        
+
         getDomRegistryDependency().registerProvider(device, bundleContext);
         device.start();
         return device;
@@ -120,9 +121,9 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co
 
     private ExecutorService getGlobalProcessingExecutor() {
         if(GLOBAL_PROCESSING_EXECUTOR == null) {
-            
+
             GLOBAL_PROCESSING_EXECUTOR = Executors.newCachedThreadPool();
-            
+
         }
         return GLOBAL_PROCESSING_EXECUTOR;
     }
@@ -130,8 +131,8 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co
     private synchronized AbstractCachingSchemaSourceProvider<String, InputStream> getGlobalNetconfSchemaProvider(BundleContext bundleContext) {
         if(GLOBAL_NETCONF_SOURCE_PROVIDER == null) {
             String storageFile = "cache/schema";
-//            File directory = bundleContext.getDataFile(storageFile);
-            File directory = new File("cache/schema");
+            //            File directory = bundleContext.getDataFile(storageFile);
+            File directory = new File(storageFile);
             SchemaSourceProvider<String> defaultProvider = SchemaSourceProviders.noopProvider();
             GLOBAL_NETCONF_SOURCE_PROVIDER = FilesystemSchemaCachingProvider.createFromStringSourceProvider(defaultProvider, directory);
         }
index 7e88ea17d01edeafef2a48c1311359ef50ef7666..c9fb1fc0b895ffabcd609eed14424e7411856413 100644 (file)
@@ -125,7 +125,7 @@ AutoCloseable {
         checkState(schemaSourceProvider != null, "Schema Source Provider must be set.")
         checkState(eventExecutor != null, "Event executor must be set.");
 
-        val listener = new NetconfDeviceListener(this, eventExecutor);
+        val listener = new NetconfDeviceListener(this);
         val task = startClientTask(dispatcher, listener)
         if (mountInstance != null) {
             commitHandlerReg = mountInstance.registerCommitHandler(ROOT_PATH, this)
index 69fe4aa1904e57ac83512400eaf6a3688a8da3ea..13cd5dbcf03a185ce99a5631684696bf74ef3ab5 100644 (file)
@@ -7,61 +7,19 @@
  */
 package org.opendaylight.controller.sal.connect.netconf;
 
-import com.google.common.base.Objects;
-
-import io.netty.util.concurrent.EventExecutor;
-import io.netty.util.concurrent.Promise;
-
-import java.util.List;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.locks.ReentrantLock;
-
-import org.eclipse.xtext.xbase.lib.Exceptions;
-import org.eclipse.xtext.xbase.lib.Functions.Function0;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.client.AbstractNetconfClientNotifySessionListener;
 import org.opendaylight.controller.netconf.client.NetconfClientSession;
-import org.opendaylight.controller.netconf.client.NetconfClientSessionListener;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
-import org.opendaylight.controller.sal.connect.netconf.NetconfDevice;
-import org.opendaylight.controller.sal.connect.netconf.NetconfMapping;
 import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.Node;
-import org.w3c.dom.Document;
-
-@SuppressWarnings("all")
-class NetconfDeviceListener extends NetconfClientSessionListener {
-    private final NetconfDevice device;
-    private final EventExecutor eventExecutor;
-
-    public NetconfDeviceListener(final NetconfDevice device, final EventExecutor eventExecutor) {
-        this.device = device;
-        this.eventExecutor = eventExecutor;
-    }
 
-    private Promise<NetconfMessage> messagePromise;
-    private ConcurrentMap<String, Promise<NetconfMessage>> promisedMessages;
+import com.google.common.base.Preconditions;
 
-    private final ReentrantLock promiseLock = new ReentrantLock();
+class NetconfDeviceListener extends AbstractNetconfClientNotifySessionListener {
+    private final NetconfDevice device;
 
-    public void onMessage(final NetconfClientSession session, final NetconfMessage message) {
-        if (isNotification(message)) {
-            this.onNotification(session, message);
-        } else {
-            try {
-                this.promiseLock.lock();
-                boolean _notEquals = (!Objects.equal(this.messagePromise, null));
-                if (_notEquals) {
-                    this.device.logger.debug("Setting promised reply {} with message {}", this.messagePromise, message);
-                    this.messagePromise.setSuccess(message);
-                    this.messagePromise = null;
-                }
-            } finally {
-                this.promiseLock.unlock();
-            }
-        }
+    public NetconfDeviceListener(final NetconfDevice device) {
+        this.device = Preconditions.checkNotNull(device);
     }
 
     /**
@@ -76,6 +34,7 @@ class NetconfDeviceListener extends NetconfClientSessionListener {
      *            NetconfClientSessionListener#onMessage(NetconfClientSession,
      *            NetconfMessage)}
      */
+    @Override
     public void onNotification(final NetconfClientSession session, final NetconfMessage message) {
         this.device.logger.debug("Received NETCONF notification.", message);
         CompositeNode domNotification = null;
@@ -92,65 +51,4 @@ class NetconfDeviceListener extends NetconfClientSessionListener {
             }
         }
     }
-
-    private static CompositeNode getNotificationBody(final CompositeNode node) {
-        List<Node<? extends Object>> _children = node.getChildren();
-        for (final Node<? extends Object> child : _children) {
-            if ((child instanceof CompositeNode)) {
-                return ((CompositeNode) child);
-            }
-        }
-        return null;
-    }
-
-    public NetconfMessage getLastMessage(final int attempts, final int attemptMsDelay) throws InterruptedException {
-        final Promise<NetconfMessage> promise = this.promiseReply();
-        this.device.logger.debug("Waiting for reply {}", promise);
-        int _plus = (attempts * attemptMsDelay);
-        final boolean messageAvailable = promise.await(_plus);
-        if (messageAvailable) {
-            try {
-                try {
-                    return promise.get();
-                } catch (Throwable _e) {
-                    throw Exceptions.sneakyThrow(_e);
-                }
-            } catch (final Throwable _t) {
-                if (_t instanceof ExecutionException) {
-                    final ExecutionException e = (ExecutionException) _t;
-                    IllegalStateException _illegalStateException = new IllegalStateException(e);
-                    throw _illegalStateException;
-                } else {
-                    throw Exceptions.sneakyThrow(_t);
-                }
-            }
-        }
-        String _plus_1 = ("Unsuccessful after " + Integer.valueOf(attempts));
-        String _plus_2 = (_plus_1 + " attempts.");
-        IllegalStateException _illegalStateException_1 = new IllegalStateException(_plus_2);
-        throw _illegalStateException_1;
-    }
-
-    public synchronized Promise<NetconfMessage> promiseReply() {
-        this.device.logger.debug("Promising reply.");
-        this.promiseLock.lock();
-        try {
-            boolean _equals = Objects.equal(this.messagePromise, null);
-            if (_equals) {
-                Promise<NetconfMessage> _newPromise = this.eventExecutor.<NetconfMessage> newPromise();
-                this.messagePromise = _newPromise;
-                return this.messagePromise;
-            }
-            return this.messagePromise;
-        } finally {
-            this.promiseLock.unlock();
-        }
-    }
-
-    public boolean isNotification(final NetconfMessage message) {
-        Document _document = message.getDocument();
-        final XmlElement xmle = XmlElement.fromDomDocument(_document);
-        String _name = xmle.getName();
-        return XmlNetconfConstants.NOTIFICATION_ELEMENT_NAME.equals(_name);
-    }
 }
index a816819cb9eb1a2ee06426ffd390833a50f7250d..c5390e540911d23865b83d53aaf55c230f1098dd 100644 (file)
@@ -7,15 +7,21 @@
  */
 package org.opendaylight.controller.sal.connect.netconf;
 
+import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.NETCONF_CANDIDATE_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.NETCONF_COMMIT_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.NETCONF_CONFIG_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.NETCONF_EDIT_CONFIG_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.NETCONF_OPERATION_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.NETCONF_RUNNING_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.NETCONF_TARGET_QNAME;
+
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.Set;
 
-import org.eclipse.xtext.xbase.lib.IterableExtensions;
-import org.opendaylight.controller.md.sal.common.api.data.DataModification;
 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.DataModification;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
@@ -28,18 +34,14 @@ import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder;
 
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
-import com.google.common.collect.Collections2;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 
-import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.*;
-
 public class NetconfDeviceTwoPhaseCommitTransaction implements DataCommitTransaction<InstanceIdentifier, CompositeNode> {
 
-    private NetconfDevice device;
+    private final NetconfDevice device;
     private final DataModification<InstanceIdentifier, CompositeNode> modification;
-    private boolean candidateSupported = true;
+    private final boolean candidateSupported = true;
 
     public NetconfDeviceTwoPhaseCommitTransaction(NetconfDevice device,
             DataModification<InstanceIdentifier, CompositeNode> modification) {
@@ -50,7 +52,7 @@ public class NetconfDeviceTwoPhaseCommitTransaction implements DataCommitTransac
 
     public void prepare() {
         for (InstanceIdentifier toRemove : modification.getRemovedConfigurationData()) {
-            sendRemove(toRemove);
+            sendDelete(toRemove);
         }
         for(Entry<InstanceIdentifier, CompositeNode> toUpdate : modification.getUpdatedConfigurationData().entrySet()) {
             sendMerge(toUpdate.getKey(),toUpdate.getValue());
@@ -62,23 +64,23 @@ public class NetconfDeviceTwoPhaseCommitTransaction implements DataCommitTransac
         sendEditRpc(createEditStructure(key, Optional.<String>absent(), Optional.of(value)));
     }
 
-    private void sendRemove(InstanceIdentifier toRemove) {
-        sendEditRpc(createEditStructure(toRemove, Optional.of("remove"), Optional.<CompositeNode> absent()));
+    private void sendDelete(InstanceIdentifier toDelete) {
+        sendEditRpc(createEditStructure(toDelete, Optional.of("delete"), Optional.<CompositeNode> absent()));
     }
 
     private void sendEditRpc(CompositeNode editStructure) {
         CompositeNodeBuilder<ImmutableCompositeNode> builder = configurationRpcBuilder();
         builder.setQName(NETCONF_EDIT_CONFIG_QNAME);
         builder.add(editStructure);
-        
+
         RpcResult<CompositeNode> rpcResult = device.invokeRpc(NETCONF_EDIT_CONFIG_QNAME, builder.toInstance());
         Preconditions.checkState(rpcResult.isSuccessful(),"Rpc Result was unsuccessful");
-        
+
     }
 
     private CompositeNodeBuilder<ImmutableCompositeNode> configurationRpcBuilder() {
         CompositeNodeBuilder<ImmutableCompositeNode> ret = ImmutableCompositeNode.builder();
-        
+
         Node<?> targetNode;
         if(candidateSupported) {
             targetNode = ImmutableCompositeNode.create(NETCONF_CANDIDATE_QNAME, ImmutableList.<Node<?>>of());
@@ -90,7 +92,7 @@ public class NetconfDeviceTwoPhaseCommitTransaction implements DataCommitTransac
         return ret;
     }
 
-    private CompositeNode createEditStructure(InstanceIdentifier dataPath, Optional<String> action,
+    private CompositeNode createEditStructure(InstanceIdentifier dataPath, Optional<String> operation,
             Optional<CompositeNode> lastChildOverride) {
         List<PathArgument> path = dataPath.getPath();
         List<PathArgument> reversed = Lists.reverse(path);
@@ -106,10 +108,10 @@ public class NetconfDeviceTwoPhaseCommitTransaction implements DataCommitTransac
             for (Entry<QName, Object> entry : predicates.entrySet()) {
                 builder.addLeaf(entry.getKey(), entry.getValue());
             }
-            
+
             if (isLast) {
-                if (action.isPresent()) {
-                    builder.setAttribute(NETCONF_ACTION_QNAME, action.get());
+                if (operation.isPresent()) {
+                    builder.setAttribute(NETCONF_OPERATION_QNAME, operation.get());
                 }
                 if (lastChildOverride.isPresent()) {
                     List<Node<?>> children = lastChildOverride.get().getChildren();
@@ -118,7 +120,7 @@ public class NetconfDeviceTwoPhaseCommitTransaction implements DataCommitTransac
                             builder.add(child);
                         }
                     }
-                    
+
                 }
             } else {
                 builder.add(previous);
@@ -130,7 +132,7 @@ public class NetconfDeviceTwoPhaseCommitTransaction implements DataCommitTransac
     }
 
     @Override
-    public RpcResult<Void> finish() throws IllegalStateException {
+    public RpcResult<Void> finish() {
         CompositeNodeBuilder<ImmutableCompositeNode> commitInput = ImmutableCompositeNode.builder();
         commitInput.setQName(NETCONF_COMMIT_QNAME);
         RpcResult<?> rpcResult = device.invokeRpc(NetconfMapping.NETCONF_COMMIT_QNAME, commitInput.toInstance());
index 76a5506df3f163a2c0ccab2f1515102c6a9b58bb..f409ecdade553e91065e85d9fc2024150e21eba5 100644 (file)
@@ -7,34 +7,39 @@
  */
 package org.opendaylight.controller.sal.connect.netconf
 
-import org.opendaylight.controller.netconf.api.NetconfMessage
-import org.opendaylight.yangtools.yang.data.api.CompositeNode
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
-import org.opendaylight.yangtools.yang.common.QName
-import org.opendaylight.yangtools.yang.common.RpcResult
-import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
+import com.google.common.base.Optional
+import com.google.common.base.Preconditions
+import com.google.common.collect.ImmutableList
 import java.net.URI
-import java.util.Collections
-import org.opendaylight.yangtools.yang.data.api.Node
-import org.opendaylight.yangtools.yang.data.impl.NodeUtils
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
 import java.util.ArrayList
-import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
+import java.util.Collections
+import java.util.List
+import java.util.Set
 import java.util.concurrent.atomic.AtomicInteger
-import org.w3c.dom.Document
-import org.w3c.dom.Element
 import org.opendaylight.controller.sal.common.util.Rpcs
-import java.util.List
-import com.google.common.collect.ImmutableList
-import org.opendaylight.yangtools.yang.data.api.SimpleNode
+import org.opendaylight.yangtools.yang.data.api.CompositeNode
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
 import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode
-import com.google.common.base.Preconditions
-import com.google.common.base.Optional
-import org.opendaylight.yangtools.yang.model.api.SchemaContext
+import java.util.Collections
+import java.util.List
+import java.util.Set
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument
+import org.opendaylight.yangtools.yang.data.api.Node
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
 import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils
 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
-import java.util.Set
+import org.opendaylight.yangtools.yang.model.api.SchemaContext
+import org.w3c.dom.Document
+import org.w3c.dom.Element
+import org.opendaylight.yangtools.yang.common.QName
+import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
+import org.opendaylight.controller.netconf.api.NetconfMessage
+import org.opendaylight.yangtools.yang.common.RpcResult
 
 class NetconfMapping {
 
@@ -51,7 +56,7 @@ class NetconfMapping {
     public static val NETCONF_GET_CONFIG_QNAME = QName.create(NETCONF_QNAME, "get-config");
     public static val NETCONF_EDIT_CONFIG_QNAME = QName.create(NETCONF_QNAME, "edit-config");
     public static val NETCONF_DELETE_CONFIG_QNAME = QName.create(NETCONF_QNAME, "delete-config");
-    public static val NETCONF_ACTION_QNAME = QName.create(NETCONF_QNAME, "action");
+    public static val NETCONF_OPERATION_QNAME = QName.create(NETCONF_QNAME, "operation");
     public static val NETCONF_COMMIT_QNAME = QName.create(NETCONF_QNAME, "commit");
     
     public static val NETCONF_CONFIG_QNAME = QName.create(NETCONF_QNAME, "config");
@@ -93,6 +98,9 @@ class NetconfMapping {
         for (arg : argument.keyValues.entrySet) {
             list.add = new SimpleNodeTOImpl(arg.key, null, arg.value);
         }
+        if (node != null) {
+            list.add(node);
+        }
         return new CompositeNodeTOImpl(argument.nodeType, null, list)
     }
 
@@ -121,9 +129,9 @@ class NetconfMapping {
     }
 
     static def NetconfMessage toRpcMessage(QName rpc, CompositeNode node,Optional<SchemaContext> ctx) {
-        val rpcPayload = wrap(NETCONF_RPC_QNAME, flattenInput(node));
-        val w3cPayload = NodeUtils.buildShadowDomTree(rpcPayload);
-        w3cPayload.documentElement.setAttribute("message-id", "m-" + messageId.andIncrement);
+        val rpcPayload = wrap(NETCONF_RPC_QNAME, flattenInput(node))
+        val w3cPayload = XmlDocumentUtils.toDocument(rpcPayload, XmlDocumentUtils.defaultValueCodecProvider)
+        w3cPayload.documentElement.setAttribute("message-id", "m-" + messageId.andIncrement)
         return new NetconfMessage(w3cPayload);
     }
     
index 49f702080cc5c6e29ce148e9c2a44f5bc32d4345..fa6b6f7ca58f4403e9c9c3b97f79fbb2aa47d2ea 100644 (file)
@@ -9,7 +9,6 @@ package org.opendaylight.controller.sal.connect.netconf;
 
 import java.util.Set;
 
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfState;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
@@ -19,7 +18,6 @@ import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder;
 import org.opendaylight.yangtools.yang.model.util.repo.SchemaSourceProvider;
 
 import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
 
 class NetconfRemoteSchemaSourceProvider implements SchemaSourceProvider<String> {
 
index a34aaff757074794cde5c4caac24670450016e74..23892e18bd4e171d41437c2b40a3ec058f4f317a 100644 (file)
@@ -7,16 +7,17 @@
  */
 package org.opendaylight.controller.sal.connect.netconf;
 
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.StringBufferInputStream;
-import java.io.StringReader;
 
 import org.opendaylight.yangtools.concepts.Delegator;
 import org.opendaylight.yangtools.yang.common.QName;
 
+import com.google.common.base.Charsets;
+
 /**
- * 
+ *
  *
  */
 public class YangModelInputStreamAdapter extends InputStream implements Delegator<InputStream> {
@@ -24,9 +25,7 @@ public class YangModelInputStreamAdapter extends InputStream implements Delegato
     final String source;
     final QName moduleIdentifier;
     final InputStream delegate;
-    
-    
-    
+
     private YangModelInputStreamAdapter(String source, QName moduleIdentifier, InputStream delegate) {
         super();
         this.source = source;
@@ -34,46 +33,57 @@ public class YangModelInputStreamAdapter extends InputStream implements Delegato
         this.delegate = delegate;
     }
 
+    @Override
     public int read() throws IOException {
         return delegate.read();
     }
 
+    @Override
     public int hashCode() {
         return delegate.hashCode();
     }
 
+    @Override
     public int read(byte[] b) throws IOException {
         return delegate.read(b);
     }
 
+    @Override
     public boolean equals(Object obj) {
         return delegate.equals(obj);
     }
 
+    @Override
     public int read(byte[] b, int off, int len) throws IOException {
         return delegate.read(b, off, len);
     }
 
+    @Override
     public long skip(long n) throws IOException {
         return delegate.skip(n);
     }
 
+    @Override
     public int available() throws IOException {
         return delegate.available();
     }
 
+    @Override
     public void close() throws IOException {
         delegate.close();
     }
 
+    @Override
     public void mark(int readlimit) {
         delegate.mark(readlimit);
     }
 
+    @Override
     public void reset() throws IOException {
         delegate.reset();
     }
 
+    @Override
     public boolean markSupported() {
         return delegate.markSupported();
     }
@@ -89,7 +99,6 @@ public class YangModelInputStreamAdapter extends InputStream implements Delegato
     }
 
     public static YangModelInputStreamAdapter create(QName name, String module) {
-        InputStream stringInput = new StringBufferInputStream(module);
-        return new YangModelInputStreamAdapter(null, name, stringInput );
+        return new YangModelInputStreamAdapter(null, name, new ByteArrayInputStream(module.getBytes(Charsets.UTF_8)));
     }
 }
index b28e72eb80251adb294d99f2e72d17c7edd7cbaf..f0fa452dc5c989138481a50ac89b120f02edb03c 100644 (file)
@@ -92,7 +92,7 @@ module odl-sal-netconf-connector-cfg {
             leaf connection-timeout-millis {
                 description "Specifies timeout in milliseconds after which connection must be established.";
                 type uint32;
-                default 5000;
+                default 20000;
             }
 
             leaf max-connection-attempts {
index b6d0632068b32d3c1b60c430bae879f2c7345c74..d4f5d43e5ed0ee077782122b124797a811bb8e42 100644 (file)
@@ -6,13 +6,20 @@
         <version>1.1-SNAPSHOT</version>
     </parent>
     <artifactId>sal-remote</artifactId>
-    <packaging>jar</packaging>
+    <packaging>bundle</packaging>
     <scm>
         <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
         <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
         <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
       <tag>HEAD</tag>
   </scm>
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-api</artifactId>
+            <version>1.1-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
     <build>
         <plugins>
             <plugin>
             </plugin>
         </plugins>
     </build>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.opendaylight.controller</groupId>
-            <artifactId>sal-binding-api</artifactId>
-            <version>1.1-SNAPSHOT</version>
-        </dependency>
-    </dependencies>
 </project>
diff --git a/opendaylight/md-sal/sal-remote/src/main/java/org/opendaylight/controller/sal/restconf/service/impl/SalRemoteServiceImpl.java b/opendaylight/md-sal/sal-remote/src/main/java/org/opendaylight/controller/sal/restconf/service/impl/SalRemoteServiceImpl.java
deleted file mode 100644 (file)
index 1da6032..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.restconf.service.impl;
-
-import java.util.concurrent.Future;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.BeginTransactionOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateDataChangeEventSubscriptionInput;
-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.CreateNotificationStreamInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateNotificationStreamOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.SalRemoteService;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-
-public class SalRemoteServiceImpl implements SalRemoteService {
-    @Override
-    public Future<RpcResult<BeginTransactionOutput>> beginTransaction() {
-        return null;
-    }
-
-    @Override
-    public Future<RpcResult<CreateDataChangeEventSubscriptionOutput>> createDataChangeEventSubscription(CreateDataChangeEventSubscriptionInput input) {
-        return null;
-    }
-
-    @Override
-    public Future<RpcResult<CreateNotificationStreamOutput>> createNotificationStream(CreateNotificationStreamInput input) {
-        return null;
-    }
-}
index cc77af57d6abf328adb553fe76e7ff2aa6fc373e..d12e252711de8834072c117831801e01f1e30865 100644 (file)
@@ -9,8 +9,8 @@ module sal-remote {
     contact "Martin Bobak <mbobak@cisco.com>";
 
     description
-          "This module contains the definition of types related to
-           Internet Assigned Numbers Authority.
+          "This module contains the definition of methods related to
+           sal remote model.
 
            Copyright (c)2013 Cisco Systems, Inc. All rights reserved.
 
@@ -48,8 +48,27 @@ module sal-remote {
 
     notification data-changed-notification {
         description "Data change notification.";
-        leaf data-change-event {
-            type instance-identifier;
+        list data-change-event {
+            key path;
+            leaf path {
+                type instance-identifier;
+            }
+            leaf store {
+                type enumeration {
+                    enum config;
+                    enum operation;
+                }
+            }
+            leaf operation {
+                type enumeration {
+                    enum created;
+                    enum updated;
+                    enum deleted;
+                }
+            }
+            anyxml data{
+                description "DataObject ";
+            }
          }
     }
 
index f511ff7e76049f4338eededef8d5725a14ce7cc8..95bb62f93b331257413f2273bcba32ce22fdc7e9 100644 (file)
@@ -40,8 +40,6 @@ public final class ZeroMQServerModule extends org.opendaylight.controller.config
         
         Broker broker = getDomBrokerDependency();
 
-
-        
         final int port = getPort() != null ? getPort() : ZEROMQ_ROUTER_PORT;
 
         ServerImpl serverImpl = new ServerImpl(port);
@@ -50,7 +48,6 @@ public final class ZeroMQServerModule extends org.opendaylight.controller.config
 
         RoutingTableProvider provider = new RoutingTableProvider(bundleContext,serverImpl);
 
-
         RemoteRpcProvider facade = new RemoteRpcProvider(serverImpl, clientImpl);
         
         facade.setRoutingTableProvider(provider );
index b5a67ff0df97f3d110f1842074617468ce836b61..5c14dd0c453ce8365e528506d743699edf418f3a 100644 (file)
@@ -40,6 +40,7 @@ import java.util.concurrent.FutureTask;
 import java.util.concurrent.TimeUnit;
 
 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
@@ -76,10 +77,6 @@ public class ServerImpl implements RemoteRpcServer, RouteChangeListener<String,
 
   public ServerImpl(int port) {
     this.port = port;
-    this.serverAddress = new StringBuilder(findIpAddress()).
-                              append(":").
-                              append(port).
-                              toString();
   }
 
   public RoutingTableProvider getRoutingTableProvider() {
@@ -134,6 +131,28 @@ public class ServerImpl implements RemoteRpcServer, RouteChangeListener<String,
         "Remote RPC Server is already running");
 
     status = State.STARTING;
+    _logger.debug("Remote RPC Server is starting...");
+
+    String hostIpAddress = findIpAddress();
+
+    //Log and silently die as per discussion in the bug (bug-362)
+    //https://bugs.opendaylight.org/show_bug.cgi?id=362
+    //
+    // A tracking enhancement defect (bug-366) is created to properly fix this issue
+    //https://bugs.opendaylight.org/show_bug.cgi?id=366
+    //checkState(hostIpAddress != null, "Remote RPC Server could not acquire host ip address");
+
+    if (hostIpAddress == null) {
+      _logger.error("Remote RPC Server could not acquire host ip address. Stopping...");
+      stop();
+      return;
+    }
+
+    this.serverAddress = new StringBuilder(hostIpAddress).
+        append(":").
+        append(port).
+        toString();
+
     context = ZMQ.context(1);
     remoteServices = new HashSet<QName>();//
     serverPool = Executors.newSingleThreadExecutor();//main server thread
@@ -334,12 +353,13 @@ public class ServerImpl implements RemoteRpcServer, RouteChangeListener<String,
    * @return
    */
   private String findIpAddress() {
-    String hostAddress = null;
     Enumeration e = null;
     try {
       e = NetworkInterface.getNetworkInterfaces();
     } catch (SocketException e1) {
-      e1.printStackTrace();
+      _logger.error("Failed to get list of interfaces", e1);
+      //throw new RuntimeException("Failed to acquire list of interfaces", e1);
+      return null;
     }
     while (e.hasMoreElements()) {
 
@@ -348,12 +368,17 @@ public class ServerImpl implements RemoteRpcServer, RouteChangeListener<String,
       Enumeration ee = n.getInetAddresses();
       while (ee.hasMoreElements()) {
         InetAddress i = (InetAddress) ee.nextElement();
-        if ((i instanceof Inet4Address) && (i.isSiteLocalAddress()))
-          hostAddress = i.getHostAddress();
+        _logger.debug("Trying address {}", i);
+        if ((i instanceof Inet4Address) && (i.isSiteLocalAddress())) {
+          String hostAddress = i.getHostAddress();
+          _logger.debug("Settled on host address {}", hostAddress);
+          return hostAddress;
+        }
       }
     }
-    return hostAddress;
 
+    _logger.error("Failed to find a suitable host address");
+    return null;
   }
 
   /**
index 17cfcbe4d443de1544982749e24e4f9434bea4f8..a4d2f4ca25d729b68eaabebf4e84d444d72b800c 100644 (file)
       <artifactId>gson</artifactId>
       <version>2.2.4</version>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-parser-impl</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-codec-http</artifactId>
+      <version>4.0.10.Final</version>
+    </dependency>
     
     <!-- Testing Dependencies -->
     <dependency>
       <version>1.0.9</version>
       <scope>test</scope>
     </dependency>
-    <dependency>
-      <groupId>org.opendaylight.yangtools</groupId>
-      <artifactId>yang-parser-impl</artifactId>
-      <scope>test</scope>
-    </dependency>
     <dependency>
       <groupId>org.glassfish.jersey.test-framework.providers</groupId>
       <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
index 848f2c48ab10e2fb12ea4ca9c67481a5f65b6528..cef5df9e579fb5c8142ca186364044c591421a91 100644 (file)
@@ -16,8 +16,10 @@ import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
 
 import org.opendaylight.controller.sal.restconf.impl.StructuredData;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
@@ -55,11 +57,36 @@ public interface RestconfService {
 
     @GET
     @Path("/modules")
-    @Produces({Draft02.MediaTypes.API+JSON,Draft02.MediaTypes.API+XML})
+    @Produces({Draft02.MediaTypes.API+XML, Draft02.MediaTypes.API+JSON,
+               MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
     public StructuredData getModules();
 
+    @GET
+    @Path("/modules/{identifier:.+}")
+    @Produces({Draft02.MediaTypes.API+XML, Draft02.MediaTypes.API+JSON,
+               MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
+    public StructuredData getModules(@PathParam("identifier") String identifier);
+
+    @GET
+    @Path("/modules/module/{identifier:.+}")
+    @Produces({Draft02.MediaTypes.API+XML, Draft02.MediaTypes.API+JSON,
+               MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
+    public StructuredData getModule(@PathParam("identifier") String identifier);
+
+    @GET
+    @Path("/operations")
+    @Produces({Draft02.MediaTypes.API+XML, Draft02.MediaTypes.API+JSON,
+               MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
+    public StructuredData getOperations();
+
+    @GET
+    @Path("/operations/{identifier:.+}")
+    @Produces({Draft02.MediaTypes.API+XML, Draft02.MediaTypes.API+JSON,
+               MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
+    public StructuredData getOperations(@PathParam("identifier") String identifier);
+
     @POST
-    @Path("/operations/{identifier}")
+    @Path("/operations/{identifier:.+}")
     @Produces({Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+XML,
                Draft02.MediaTypes.DATA+JSON, Draft02.MediaTypes.DATA+XML,
                MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
@@ -69,7 +96,7 @@ public interface RestconfService {
     public StructuredData invokeRpc(@PathParam("identifier") String identifier, CompositeNode payload);
     
     @POST
-    @Path("/operations/{identifier}")
+    @Path("/operations/{identifier:.+}")
     @Produces({Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+XML,
                Draft02.MediaTypes.DATA+JSON, Draft02.MediaTypes.DATA+XML,
                MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
@@ -109,4 +136,8 @@ public interface RestconfService {
     @Path("/config/{identifier:.+}")
     public Response deleteConfigurationData(@PathParam("identifier") String identifier);
 
+    @GET
+    @Path("/streams/stream/{identifier:.+}")
+    public Response subscribeToStream(@PathParam("identifier") String identifier, @Context UriInfo uriInfo);
+
 }
index 226eff44e133a7ad311253740d6d77ea28a1d411..d1441d7b9d904a202ad90bfcc53d36c794ae993e 100644 (file)
@@ -203,7 +203,6 @@ class JsonMapper {
                     + baseType.getClass().getSimpleName() + ".");
         }
 
-        // TODO check InstanceIdentifierTypeDefinition
         if (baseType instanceof IdentityrefTypeDefinition) {
             if (node.getValue() instanceof QName) {
                 IdentityValuesDTO valueDTO = (IdentityValuesDTO) RestCodec.from(baseType, mountPoint).serialize(
index ea5108ee433e0b48dc817bfd6c5f02c75ae5f471..1870bdf0bf37daf6e5e0acaee273b90ce3c749a5 100644 (file)
@@ -18,6 +18,7 @@ import org.opendaylight.controller.sal.core.api.model.SchemaService;
 import org.opendaylight.controller.sal.core.api.mount.MountService;
 import org.opendaylight.controller.sal.restconf.impl.BrokerFacade;
 import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
+import org.opendaylight.controller.sal.streams.websockets.WebSocketServer;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener;
 import org.osgi.framework.BundleActivator;
@@ -34,6 +35,7 @@ public class RestconfProvider implements BundleActivator, Provider, ServiceTrack
     private ServiceTracker<Broker, Broker> brokerServiceTrancker;
     private BundleContext bundleContext;
     private ProviderSession session;
+    private Thread webSocketServerThread;
 
     @Override
     public void onSessionInitiated(ProviderSession session) {
@@ -53,6 +55,9 @@ public class RestconfProvider implements BundleActivator, Provider, ServiceTrack
         bundleContext = context;
         brokerServiceTrancker = new ServiceTracker<>(context, Broker.class, this);
         brokerServiceTrancker.open();
+        webSocketServerThread = new Thread(new WebSocketServer());
+        webSocketServerThread.setName("Web socket server");
+        webSocketServerThread.start();
     }
 
     @Override
@@ -64,6 +69,7 @@ public class RestconfProvider implements BundleActivator, Provider, ServiceTrack
                 e.printStackTrace();
             }
         }
+        webSocketServerThread.interrupt();
         session.close();
         brokerServiceTrancker.close();
     }
index 22e08d97f476679e5103779ccb6d6cec3a4d04fa..5dba7474caa22affe5d73594ff918de54f1d4c5f 100644 (file)
@@ -31,8 +31,8 @@ import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import com.google.gson.stream.JsonWriter;
 
 @Provider
-@Produces({ Draft02.MediaTypes.DATA + RestconfService.JSON, Draft02.MediaTypes.OPERATION + RestconfService.JSON,
-        MediaType.APPLICATION_JSON })
+@Produces({ Draft02.MediaTypes.API + RestconfService.JSON, Draft02.MediaTypes.DATA + RestconfService.JSON,
+        Draft02.MediaTypes.OPERATION + RestconfService.JSON, MediaType.APPLICATION_JSON })
 public enum StructuredDataToJsonProvider implements MessageBodyWriter<StructuredData> {
     INSTANCE;
 
index b6d8c953a9219a6c9b7b59cb0128c9b8b2ee98ae..7d6b329cfa2ac57a731f94934fa99f3acf04ca9f 100644 (file)
@@ -37,8 +37,8 @@ import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 
 @Provider
-@Produces({ Draft02.MediaTypes.DATA + RestconfService.XML, Draft02.MediaTypes.OPERATION + RestconfService.XML,
-        MediaType.APPLICATION_XML, MediaType.TEXT_XML })
+@Produces({ Draft02.MediaTypes.API + RestconfService.XML, Draft02.MediaTypes.DATA + RestconfService.XML,
+        Draft02.MediaTypes.OPERATION + RestconfService.XML, MediaType.APPLICATION_XML, MediaType.TEXT_XML })
 public enum StructuredDataToXmlProvider implements MessageBodyWriter<StructuredData> {
     INSTANCE;
 
index 67429f3759283209b49f971746e67928ba076012..d3050061da829852c494a55c05ef8e61a113acd0 100644 (file)
@@ -11,13 +11,14 @@ import javax.ws.rs.core.Response
 import org.opendaylight.controller.md.sal.common.api.data.DataReader
 import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession
 import org.opendaylight.controller.sal.core.api.data.DataBrokerService
+import org.opendaylight.controller.sal.core.api.mount.MountInstance
 import org.opendaylight.controller.sal.rest.impl.RestconfProvider
+import org.opendaylight.controller.sal.streams.listeners.ListenerAdapter
 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.slf4j.LoggerFactory
-import org.opendaylight.controller.sal.core.api.mount.MountInstance
 
 class BrokerFacade implements DataReader<InstanceIdentifier, CompositeNode> {
 
@@ -133,4 +134,13 @@ class BrokerFacade implements DataReader<InstanceIdentifier, CompositeNode> {
         return transaction.commit
     }
 
+    def registerToListenDataChanges(ListenerAdapter listener) {
+        checkPreconditions
+        if (listener.listening) {
+            return;
+        }
+        val registration = dataService.registerDataChangeListener(listener.path, listener)
+        listener.setRegistration(registration)
+    }
+
 }
index 2dfe5062c89af5b2f0151dfee3721d0ba7486521..c2b82eae632290cc60d48df245d70fa1c583e8b8 100644 (file)
@@ -8,9 +8,11 @@
 package org.opendaylight.controller.sal.restconf.impl
 
 import com.google.common.base.Preconditions
+import com.google.common.base.Splitter
 import com.google.common.collect.BiMap
 import com.google.common.collect.FluentIterable
 import com.google.common.collect.HashBiMap
+import com.google.common.collect.Lists
 import java.net.URI
 import java.net.URLDecoder
 import java.net.URLEncoder
@@ -86,27 +88,55 @@ class ControllerContext implements SchemaServiceListener {
         onGlobalContextUpdated(schemas)
     }
 
-    public def InstanceIdWithSchemaNode toInstanceIdentifier(String restconfInstance) {
+    def InstanceIdWithSchemaNode toInstanceIdentifier(String restconfInstance) {
+        return restconfInstance.toIdentifier(false)
+    }
+
+    def InstanceIdWithSchemaNode toMountPointIdentifier(String restconfInstance) {
+        return restconfInstance.toIdentifier(true)
+    }
+
+    private def InstanceIdWithSchemaNode toIdentifier(String restconfInstance, boolean toMountPointIdentifier) {
         checkPreconditions
-        val pathArgs = restconfInstance.split("/");
+        val pathArgs = Lists.newArrayList(Splitter.on("/").split(restconfInstance))
+        pathArgs.omitFirstAndLastEmptyString
         if (pathArgs.empty) {
             return null;
         }
-        if (pathArgs.head.empty) {
-            pathArgs.remove(0)
-        }
         val startModule = pathArgs.head.toModuleName();
         if (startModule === null) {
             throw new ResponseException(BAD_REQUEST, "First node in URI has to be in format \"moduleName:nodeName\"")
         }
-        val iiWithSchemaNode = collectPathArguments(InstanceIdentifier.builder(), pathArgs,
-            globalSchema.getLatestModule(startModule), null);
+        var InstanceIdWithSchemaNode iiWithSchemaNode = null;
+        if (toMountPointIdentifier) {
+            iiWithSchemaNode = collectPathArguments(InstanceIdentifier.builder(), pathArgs,
+            globalSchema.getLatestModule(startModule), null, true);
+        } else {
+            iiWithSchemaNode = collectPathArguments(InstanceIdentifier.builder(), pathArgs,
+            globalSchema.getLatestModule(startModule), null, false);
+        }
         if (iiWithSchemaNode === null) {
             throw new ResponseException(BAD_REQUEST, "URI has bad format")
         }
         return iiWithSchemaNode
     }
 
+    private def omitFirstAndLastEmptyString(List<String> list) {
+        if (list.empty) {
+            return list;
+        }
+        if (list.head.empty) {
+            list.remove(0)
+        }
+        if (list.empty) {
+            return list;
+        }
+        if (list.last.empty) {
+            list.remove(list.indexOf(list.last))
+        }
+        return list;
+    }
+
     private def getLatestModule(SchemaContext schema, String moduleName) {
         checkArgument(schema !== null);
         checkArgument(moduleName !== null && !moduleName.empty)
@@ -150,31 +180,63 @@ class ControllerContext implements SchemaServiceListener {
         return moduleSchemas?.filterLatestModule
     }
 
+    def findModuleByNameAndRevision(QName module) {
+        checkPreconditions
+        checkArgument(module !== null && module.localName !== null && module.revision !== null)
+        return globalSchema.findModuleByName(module.localName, module.revision)
+    }
+
+    def findModuleByNameAndRevision(MountInstance mountPoint, QName module) {
+        checkPreconditions
+        checkArgument(module !== null && module.localName !== null && module.revision !== null && mountPoint !== null)
+        return mountPoint.schemaContext?.findModuleByName(module.localName, module.revision)
+    }
+
+    def getDataNodeContainerFor(InstanceIdentifier path) {
+        checkPreconditions
+        val elements = path.path;
+        val startQName = elements.head.nodeType;
+        val initialModule = globalSchema.findModuleByNamespaceAndRevision(startQName.namespace, startQName.revision)
+        var node = initialModule as DataNodeContainer;
+        for (element : elements) {
+            val potentialNode = node.childByQName(element.nodeType);
+            if (potentialNode === null || !potentialNode.listOrContainer) {
+                return null
+            }
+            node = potentialNode as DataNodeContainer
+        }
+        return node
+    }
+
     def String toFullRestconfIdentifier(InstanceIdentifier path) {
         checkPreconditions
         val elements = path.path;
         val ret = new StringBuilder();
-        val startQName = elements.get(0).nodeType;
+        val startQName = elements.head.nodeType;
         val initialModule = globalSchema.findModuleByNamespaceAndRevision(startQName.namespace, startQName.revision)
-        var node = initialModule as DataSchemaNode;
+        var node = initialModule as DataNodeContainer;
         for (element : elements) {
-            node = node.childByQName(element.nodeType);
-            ret.append(element.toRestconfIdentifier(node));
+            val potentialNode = node.childByQName(element.nodeType);
+            if (!potentialNode.listOrContainer) {
+                return null
+            }
+            node = potentialNode as DataNodeContainer
+            ret.append(element.convertToRestconfIdentifier(node));
         }
         return ret.toString
     }
 
-    private def dispatch CharSequence toRestconfIdentifier(NodeIdentifier argument, DataSchemaNode node) {
+    private def dispatch CharSequence convertToRestconfIdentifier(NodeIdentifier argument, ContainerSchemaNode node) {
         '''/«argument.nodeType.toRestconfIdentifier()»'''
     }
 
-    private def dispatch CharSequence toRestconfIdentifier(NodeIdentifierWithPredicates argument, ListSchemaNode node) {
+    private def dispatch CharSequence convertToRestconfIdentifier(NodeIdentifierWithPredicates argument, ListSchemaNode node) {
         val nodeIdentifier = argument.nodeType.toRestconfIdentifier();
         val keyValues = argument.keyValues;
         return '''/«nodeIdentifier»/«FOR key : node.keyDefinition SEPARATOR "/"»«keyValues.get(key).toUriString»«ENDFOR»'''
     }
 
-    private def dispatch CharSequence toRestconfIdentifier(PathArgument argument, DataSchemaNode node) {
+    private def dispatch CharSequence convertToRestconfIdentifier(PathArgument argument, DataNodeContainer node) {
         throw new IllegalArgumentException("Conversion of generic path argument is not supported");
     }
 
@@ -211,6 +273,16 @@ class ControllerContext implements SchemaServiceListener {
         return module?.namespace
     }
 
+    def getAllModules(MountInstance mountPoint) {
+        checkPreconditions
+        return mountPoint?.schemaContext?.modules
+    }
+    
+    def getAllModules() {
+        checkPreconditions
+        return globalSchema.modules
+    }
+
     def CharSequence toRestconfIdentifier(QName qname) {
         checkPreconditions
         var module = uriToModuleName.get(qname.namespace)
@@ -253,6 +325,10 @@ class ControllerContext implements SchemaServiceListener {
         return container.dataNodeChildByQName(name);
     }
 
+    private static dispatch def DataSchemaNode childByQName(Module container, QName name) {
+        return container.dataNodeChildByQName(name);
+    }
+
     private static dispatch def DataSchemaNode childByQName(DataSchemaNode container, QName name) {
         return null;
     }
@@ -281,7 +357,7 @@ class ControllerContext implements SchemaServiceListener {
     }
     
     private def InstanceIdWithSchemaNode collectPathArguments(InstanceIdentifierBuilder builder, List<String> strings,
-        DataNodeContainer parentNode, MountInstance mountPoint) {
+        DataNodeContainer parentNode, MountInstance mountPoint, boolean returnJustMountPoint) {
         checkNotNull(strings)
         if (parentNode === null) {
             return null;
@@ -318,6 +394,10 @@ class ControllerContext implements SchemaServiceListener {
                     throw new ResponseException(BAD_REQUEST, "Mount point does not contain any schema with modules.")
                 }
                 
+                if (returnJustMountPoint) {
+                    return new InstanceIdWithSchemaNode(InstanceIdentifier.builder().toInstance, mountPointSchema, mount)
+                }
+                
                 if (strings.size == 1) { // any data node is not behind mount point
                     return new InstanceIdWithSchemaNode(InstanceIdentifier.builder().toInstance, mountPointSchema, mount)
                 }
@@ -335,7 +415,7 @@ class ControllerContext implements SchemaServiceListener {
                 }
                 
                 return collectPathArguments(InstanceIdentifier.builder(), strings.subList(1, strings.size),
-                    moduleBehindMountPoint, mount);
+                    moduleBehindMountPoint, mount, returnJustMountPoint);
             }
             
             var Module module = null;
@@ -375,7 +455,7 @@ class ControllerContext implements SchemaServiceListener {
             }
         }
         
-        if (!(targetNode instanceof ListSchemaNode) && !(targetNode instanceof ContainerSchemaNode)) {
+        if (!targetNode.isListOrContainer) {
             throw new ResponseException(BAD_REQUEST,"URI has bad format. Node \"" + strings.head + "\" must be Container or List yang type.")
         }
         // Number of consumed elements
@@ -412,7 +492,7 @@ class ControllerContext implements SchemaServiceListener {
         }
         if (targetNode instanceof DataNodeContainer) {
             val remaining = strings.subList(consumed, strings.length);
-            val result = builder.collectPathArguments(remaining, targetNode as DataNodeContainer, mountPoint);
+            val result = builder.collectPathArguments(remaining, targetNode as DataNodeContainer, mountPoint, returnJustMountPoint);
             return result
         }
 
@@ -498,14 +578,24 @@ class ControllerContext implements SchemaServiceListener {
     private def QName toQName(String name) {
         val module = name.toModuleName;
         val node = name.toNodeName;
-        val namespace = FluentIterable.from(globalSchema.modules.sort[o1,o2 | o1.revision.compareTo(o2.revision)]) //
+        val namespace = FluentIterable.from(globalSchema.modules.sort[o1,o2 | o1.revision.compareTo(o2.revision)])
             .transform[QName.create(namespace,revision,it.name)].findFirst[module == localName]
-        ;
-        return QName.create(namespace,node);
+        if (namespace === null) {
+            return null
+        }
+        return QName.create(namespace, node);
+    }
+
+    private def boolean isListOrContainer(DataSchemaNode node) {
+        return ((node instanceof ListSchemaNode) || (node instanceof ContainerSchemaNode))
     }
 
     def getRpcDefinition(String name) {
-        return qnameToRpc.get(name.toQName)
+        val validName = name.toQName
+        if (validName === null) {
+            return null
+        }
+        return qnameToRpc.get(validName)
     }
 
     override onGlobalContextUpdated(SchemaContext context) {
index cbfc3edf2cbf10ba164820aba15aa82749f0dbdd..cfbce736fb70041ad2ee03eb26fdbc47d4c86797 100644 (file)
@@ -8,14 +8,22 @@
 package org.opendaylight.controller.sal.restconf.impl
 
 import com.google.common.base.Preconditions
+import com.google.common.base.Splitter
+import com.google.common.collect.Lists
 import java.net.URI
+import java.text.ParseException
+import java.text.SimpleDateFormat
 import java.util.ArrayList
 import java.util.HashMap
 import java.util.List
+import java.util.Set
 import javax.ws.rs.core.Response
+import javax.ws.rs.core.UriInfo
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus
 import org.opendaylight.controller.sal.core.api.mount.MountInstance
 import org.opendaylight.controller.sal.rest.api.RestconfService
+import org.opendaylight.controller.sal.streams.listeners.Notificator
+import org.opendaylight.controller.sal.streams.websockets.WebSocketServer
 import org.opendaylight.yangtools.yang.common.QName
 import org.opendaylight.yangtools.yang.common.RpcResult
 import org.opendaylight.yangtools.yang.data.api.CompositeNode
@@ -34,6 +42,9 @@ import org.opendaylight.yangtools.yang.model.api.RpcDefinition
 import org.opendaylight.yangtools.yang.model.api.SchemaContext
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition
 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition
+import org.opendaylight.yangtools.yang.model.util.EmptyType
+import org.opendaylight.yangtools.yang.parser.builder.impl.ContainerSchemaNodeBuilder
+import org.opendaylight.yangtools.yang.parser.builder.impl.LeafSchemaNodeBuilder
 
 import static javax.ws.rs.core.Response.Status.*
 
@@ -41,6 +52,17 @@ class RestconfImpl implements RestconfService {
 
     val static RestconfImpl INSTANCE = new RestconfImpl
     val static MOUNT_POINT_MODULE_NAME = "ietf-netconf"
+    val static REVISION_FORMAT = new SimpleDateFormat("yyyy-MM-dd")
+    val static RESTCONF_MODULE_DRAFT02_REVISION = "2013-10-19"
+    val static RESTCONF_MODULE_DRAFT02_NAME = "ietf-restconf"
+    val static RESTCONF_MODULE_DRAFT02_NAMESPACE = "urn:ietf:params:xml:ns:yang:ietf-restconf"
+    val static RESTCONF_MODULE_DRAFT02_RESTCONF_GROUPING_SCHEMA_NODE = "restconf"
+    val static RESTCONF_MODULE_DRAFT02_RESTCONF_CONTAINER_SCHEMA_NODE = "restconf"
+    val static RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE = "modules"
+    val static RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE = "module"
+    val static RESTCONF_MODULE_DRAFT02_OPERATIONS_CONTAINER_SCHEMA_NODE = "operations"
+    val static SAL_REMOTE_NAMESPACE = "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote"
+    val static SAL_REMOTE_RPC_SUBSRCIBE = "create-data-change-event-subscription"
 
     @Property
     BrokerFacade broker
@@ -59,7 +81,148 @@ class RestconfImpl implements RestconfService {
     }
 
     override getModules() {
-        throw new UnsupportedOperationException("TODO: auto-generated method stub")
+        val restconfModule = getRestconfModule()
+        val List<Node<?>> modulesAsData = new ArrayList
+        val moduleSchemaNode = restconfModule.getSchemaNode(RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE)
+        for (module : allModules) {
+            modulesAsData.add(module.toModuleCompositeNode(moduleSchemaNode))
+        }
+        val modulesSchemaNode = restconfModule.getSchemaNode(RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE)
+        val modulesNode = NodeFactory.createImmutableCompositeNode(modulesSchemaNode.QName, null, modulesAsData)
+        return new StructuredData(modulesNode, modulesSchemaNode, null)
+    }
+
+    override getModules(String identifier) {
+        var Set<Module> modules = null
+        var MountInstance mountPoint = null
+        if (identifier.contains(ControllerContext.MOUNT)) {
+            mountPoint = identifier.toMountPointIdentifier.mountPoint
+            modules = mountPoint.allModules
+        } else {
+            throw new ResponseException(BAD_REQUEST, "URI has bad format. If modules behind mount point should be showed, URI has to end with " + ControllerContext.MOUNT)
+        }
+        val List<Node<?>> modulesAsData = new ArrayList
+        val moduleSchemaNode = restconfModule.getSchemaNode(RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE)
+        for (module : modules) {
+            modulesAsData.add(module.toModuleCompositeNode(moduleSchemaNode))
+        }
+        val modulesSchemaNode = restconfModule.getSchemaNode(RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE)
+        val modulesNode = NodeFactory.createImmutableCompositeNode(modulesSchemaNode.QName, null, modulesAsData)
+        return new StructuredData(modulesNode, modulesSchemaNode, mountPoint)
+    }
+
+    override getModule(String identifier) {
+        val moduleNameAndRevision = identifier.moduleNameAndRevision
+        var Module module = null
+        var MountInstance mountPoint = null
+        if (identifier.contains(ControllerContext.MOUNT)) {
+            mountPoint = identifier.toMountPointIdentifier.mountPoint
+            module = mountPoint.findModuleByNameAndRevision(moduleNameAndRevision)
+        } else {
+            module = findModuleByNameAndRevision(moduleNameAndRevision)
+        }
+        if (module === null) {
+            throw new ResponseException(BAD_REQUEST,
+                "Module with name '" + moduleNameAndRevision.localName + "' and revision '" +
+                    moduleNameAndRevision.revision + "' was not found.")
+        }
+        val moduleSchemaNode = restconfModule.getSchemaNode(RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE)
+        val moduleNode = module.toModuleCompositeNode(moduleSchemaNode)
+        return new StructuredData(moduleNode, moduleSchemaNode, mountPoint)
+    }
+
+    override getOperations() {
+        return operationsFromModulesToStructuredData(allModules,null)
+    }
+    
+    override getOperations(String identifier) {
+        var Set<Module> modules = null
+        var MountInstance mountPoint = null
+        if (identifier.contains(ControllerContext.MOUNT)) {
+            mountPoint = identifier.toMountPointIdentifier.mountPoint
+            modules = mountPoint.allModules
+        } else {
+            throw new ResponseException(BAD_REQUEST, "URI has bad format. If operations behind mount point should be showed, URI has to end with " + ControllerContext.MOUNT)
+        }
+        return operationsFromModulesToStructuredData(modules,mountPoint)
+    }
+    
+    private def StructuredData operationsFromModulesToStructuredData(Set<Module> modules,MountInstance mountPoint) {
+        val List<Node<?>> operationsAsData = new ArrayList
+        val operationsSchemaNode = restconfModule.getSchemaNode(RESTCONF_MODULE_DRAFT02_OPERATIONS_CONTAINER_SCHEMA_NODE)        
+        val fakeOperationsSchemaNode = new ContainerSchemaNodeBuilder(RESTCONF_MODULE_DRAFT02_NAME, 0, operationsSchemaNode.QName, operationsSchemaNode.path)
+        for (module : modules) {
+            for (rpc : module.rpcs) {
+                operationsAsData.add(NodeFactory.createImmutableSimpleNode(rpc.QName, null, null))
+                val fakeRpcSchemaNode = new LeafSchemaNodeBuilder(module.name, 0, rpc.QName, null)
+                fakeRpcSchemaNode.setAugmenting(true)
+                fakeRpcSchemaNode.setType(EmptyType.instance)
+                fakeOperationsSchemaNode.addChildNode(fakeRpcSchemaNode.build)                
+            }
+        }
+        val operationsNode = NodeFactory.createImmutableCompositeNode(operationsSchemaNode.QName, null, operationsAsData)
+        return new StructuredData(operationsNode, fakeOperationsSchemaNode.build, mountPoint)        
+    }
+
+    private def Module getRestconfModule() {
+        val restconfModule = findModuleByNameAndRevision(
+            QName.create(RESTCONF_MODULE_DRAFT02_NAMESPACE, RESTCONF_MODULE_DRAFT02_REVISION,
+                RESTCONF_MODULE_DRAFT02_NAME))
+        if (restconfModule === null) {
+            throw new ResponseException(INTERNAL_SERVER_ERROR, "Restconf module was not found.")
+        }
+        return restconfModule
+    }
+
+    private def QName getModuleNameAndRevision(String identifier) {
+        val indexOfMountPointFirstLetter = identifier.indexOf(ControllerContext.MOUNT)
+        var moduleNameAndRevision = "";
+        if (indexOfMountPointFirstLetter !== -1) { // module and revision is behind mount point string
+            moduleNameAndRevision = identifier.substring(indexOfMountPointFirstLetter + ControllerContext.MOUNT.length)
+        } else (
+            moduleNameAndRevision = identifier
+        )
+        val pathArgs = Lists.newArrayList(Splitter.on("/").omitEmptyStrings.split(moduleNameAndRevision))
+        if (pathArgs.length < 2) {
+            throw new ResponseException(BAD_REQUEST,
+                "URI has bad format. End of URI should be in format 'moduleName/yyyy-MM-dd'")
+        }
+        try {
+            val moduleName = pathArgs.head
+            val moduleRevision = REVISION_FORMAT.parse(pathArgs.get(1))
+            return QName.create(null, moduleRevision, moduleName)
+        } catch(ParseException e) {
+            throw new ResponseException(BAD_REQUEST, "URI has bad format. It should be 'moduleName/yyyy-MM-dd'")
+        }
+    }
+
+    private def CompositeNode toModuleCompositeNode(Module module, DataSchemaNode moduleSchemaNode) {
+        val List<Node<?>> moduleNodeValues = new ArrayList
+        val nameSchemaNode = (moduleSchemaNode as DataNodeContainer).findInstanceDataChildrenByName("name").head
+        moduleNodeValues.add(NodeFactory.createImmutableSimpleNode(nameSchemaNode.QName, null, module.name))
+        val revisionSchemaNode = (moduleSchemaNode as DataNodeContainer).findInstanceDataChildrenByName("revision").head
+        moduleNodeValues.add(NodeFactory.createImmutableSimpleNode(revisionSchemaNode.QName, null, REVISION_FORMAT.format(module.revision)))
+        val namespaceSchemaNode = (moduleSchemaNode as DataNodeContainer).findInstanceDataChildrenByName("namespace").head
+        moduleNodeValues.add(NodeFactory.createImmutableSimpleNode(namespaceSchemaNode.QName, null, module.namespace.toString))
+        val featureSchemaNode = (moduleSchemaNode as DataNodeContainer).findInstanceDataChildrenByName("feature").head
+        for (feature : module.features) {
+            moduleNodeValues.add(NodeFactory.createImmutableSimpleNode(featureSchemaNode.QName, null, feature.QName.localName))
+        }
+        return NodeFactory.createImmutableCompositeNode(moduleSchemaNode.QName, null, moduleNodeValues)
+    }
+
+    private def DataSchemaNode getSchemaNode(Module restconfModule, String schemaNodeName) {
+        val restconfGrouping = restconfModule.groupings.filter[g|g.QName.localName == RESTCONF_MODULE_DRAFT02_RESTCONF_GROUPING_SCHEMA_NODE].head
+        val restconfContainer = restconfGrouping.findInstanceDataChildrenByName(RESTCONF_MODULE_DRAFT02_RESTCONF_CONTAINER_SCHEMA_NODE).head
+        if (schemaNodeName == RESTCONF_MODULE_DRAFT02_OPERATIONS_CONTAINER_SCHEMA_NODE) {
+            return (restconfContainer as DataNodeContainer).findInstanceDataChildrenByName(RESTCONF_MODULE_DRAFT02_OPERATIONS_CONTAINER_SCHEMA_NODE).head
+        } else if (schemaNodeName == RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE) {
+            return (restconfContainer as DataNodeContainer).findInstanceDataChildrenByName(RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE).head
+        } else if (schemaNodeName == RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE) {
+            val modules = (restconfContainer as DataNodeContainer).findInstanceDataChildrenByName(RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE).head
+            return (modules as DataNodeContainer).findInstanceDataChildrenByName(RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE).head
+        }
+        return null
     }
 
     override getRoot() {
@@ -67,6 +230,36 @@ class RestconfImpl implements RestconfService {
     }
 
     override invokeRpc(String identifier, CompositeNode payload) {
+        val rpc = identifier.rpcDefinition
+        if (rpc === null) {
+            throw new ResponseException(NOT_FOUND, "RPC does not exist.");
+        }
+        if (rpc.QName.namespace.toString == SAL_REMOTE_NAMESPACE && rpc.QName.localName == SAL_REMOTE_RPC_SUBSRCIBE) {
+            val value = normalizeNode(payload, rpc.input, null)
+            val pathNode = value?.getFirstSimpleByName(QName.create(rpc.QName, "path"))
+            val pathValue = pathNode?.value
+            if (pathValue === null && !(pathValue instanceof InstanceIdentifier)) {
+                throw new ResponseException(INTERNAL_SERVER_ERROR, "Instance identifier was not normalized correctly.");
+            }
+            val pathIdentifier = (pathValue as InstanceIdentifier)
+            var String streamName = null
+            if (!pathIdentifier.path.nullOrEmpty) {
+                streamName = Notificator.createStreamNameFromUri(pathIdentifier.toFullRestconfIdentifier)
+            }
+            if (streamName.nullOrEmpty) {
+                throw new ResponseException(BAD_REQUEST, "Path is empty or contains data node which is not Container or List build-in type.");
+            }
+            val streamNameNode = NodeFactory.createImmutableSimpleNode(QName.create(rpc.output.QName, "stream-name"), null, streamName)
+            val List<Node<?>> output = new ArrayList
+            output.add(streamNameNode)
+            val responseData = NodeFactory.createMutableCompositeNode(rpc.output.QName, null, output, null, null)
+
+            if (!Notificator.existListenerFor(pathIdentifier)) {
+                Notificator.createListener(pathIdentifier, streamName)
+            }
+
+            return new StructuredData(responseData, rpc.output, null)
+        }
         return callRpc(identifier.rpcDefinition, payload)
     }
 
@@ -224,6 +417,21 @@ class RestconfImpl implements RestconfService {
         }
     }
 
+    override subscribeToStream(String identifier, UriInfo uriInfo) {
+        val streamName = Notificator.createStreamNameFromUri(identifier)
+        if (streamName.nullOrEmpty) {
+            throw new ResponseException(BAD_REQUEST, "Stream name is empty.")
+        }
+        val listener = Notificator.getListenerFor(streamName);
+        if (listener === null) {
+            throw new ResponseException(BAD_REQUEST, "Stream was not found.")
+        }
+        broker.registerToListenDataChanges(listener)
+        val uriBuilder = uriInfo.getAbsolutePathBuilder()
+        val uriToWebsocketServer = uriBuilder.port(WebSocketServer.PORT).replacePath(streamName).build()
+        return Response.status(OK).location(uriToWebsocketServer).build
+    }
+
     private def dispatch URI namespace(CompositeNode data) {
         return data.nodeType.namespace
     }
diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/ListenerAdapter.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/ListenerAdapter.java
new file mode 100644 (file)
index 0000000..fdd6ba0
--- /dev/null
@@ -0,0 +1,406 @@
+package org.opendaylight.controller.sal.streams.listeners;
+
+import io.netty.channel.Channel;
+import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
+import io.netty.util.internal.ConcurrentSet;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.Executors;
+
+import javax.activation.UnsupportedDataTypeException;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.sal.core.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.rest.impl.XmlMapper;
+import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import com.google.common.base.Preconditions;
+import com.google.common.eventbus.AsyncEventBus;
+import com.google.common.eventbus.EventBus;
+import com.google.common.eventbus.Subscribe;
+
+public class ListenerAdapter implements DataChangeListener {
+
+    private static final Logger logger = LoggerFactory.getLogger(ListenerAdapter.class);
+    private final XmlMapper xmlMapper = new XmlMapper();
+    private final SimpleDateFormat rfc3339 = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ssZ");
+
+    private final InstanceIdentifier path;
+    private ListenerRegistration<DataChangeListener> registration;
+    private final String streamName;
+    private Set<Channel> subscribers = new ConcurrentSet<>();
+    private final EventBus eventBus;
+    private final EventBusChangeRecorder eventBusChangeRecorder;
+
+    ListenerAdapter(InstanceIdentifier path, String streamName) {
+        Preconditions.checkNotNull(path);
+        Preconditions.checkArgument(streamName != null && !streamName.isEmpty());
+        this.path = path;
+        this.streamName = streamName;
+        eventBus = new AsyncEventBus(Executors.newSingleThreadExecutor());
+        eventBusChangeRecorder = new EventBusChangeRecorder();
+        eventBus.register(eventBusChangeRecorder);
+    }
+
+    @Override
+    public void onDataChanged(DataChangeEvent<InstanceIdentifier, CompositeNode> change) {
+        if (!change.getCreatedConfigurationData().isEmpty() || !change.getCreatedOperationalData().isEmpty()
+                || !change.getUpdatedConfigurationData().isEmpty() || !change.getUpdatedOperationalData().isEmpty()
+                || !change.getRemovedConfigurationData().isEmpty() || !change.getRemovedOperationalData().isEmpty()) {
+            String xml = prepareXmlFrom(change);
+            Event event = new Event(EventType.NOTIFY);
+            event.setData(xml);
+            eventBus.post(event);
+        }
+    }
+
+    private final class EventBusChangeRecorder {
+        @Subscribe public void recordCustomerChange(Event event) {
+            if (event.getType() == EventType.REGISTER) {
+                Channel subscriber = event.getSubscriber();
+                if (!subscribers.contains(subscriber)) {
+                    subscribers.add(subscriber);
+                }
+            } else if (event.getType() == EventType.DEREGISTER) {
+                subscribers.remove(event.getSubscriber());
+                Notificator.removeListenerIfNoSubscriberExists(ListenerAdapter.this);
+            } else if (event.getType() == EventType.NOTIFY) {
+                for (Channel subscriber : subscribers) {
+                    if (subscriber.isActive()) {
+                        logger.debug("Data are sent to subscriber {}:", subscriber.remoteAddress());
+                        subscriber.writeAndFlush(new TextWebSocketFrame(event.getData()));
+                    } else {
+                        logger.debug("Subscriber {} is removed - channel is not active yet.", subscriber.remoteAddress());
+                        subscribers.remove(subscriber);
+                    }
+                }
+            }
+        }
+    }
+
+    private final class Event {
+        private final EventType type;
+        private Channel subscriber;
+        private String data;
+
+        public Event(EventType type) {
+            this.type = type;
+        }
+
+        public Channel getSubscriber() {
+            return subscriber;
+        }
+
+        public void setSubscriber(Channel subscriber) {
+            this.subscriber = subscriber;
+        }
+
+        public String getData() {
+            return data;
+        }
+
+        public void setData(String data) {
+            this.data = data;
+        }
+
+        public EventType getType() {
+            return type;
+        }
+    }
+
+    private enum EventType {
+        REGISTER,
+        DEREGISTER,
+        NOTIFY;
+    }
+
+    private String prepareXmlFrom(DataChangeEvent<InstanceIdentifier, CompositeNode> change) {
+        Document doc = createDocument();
+        Element notificationElement = doc.createElementNS("urn:ietf:params:xml:ns:netconf:notification:1.0",
+                "notification");
+        doc.appendChild(notificationElement);
+
+        Element eventTimeElement = doc.createElement("eventTime");
+        eventTimeElement.setTextContent(toRFC3339(new Date()));
+        notificationElement.appendChild(eventTimeElement);
+
+        Element dataChangedNotificationEventElement = doc.createElementNS(
+                "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote", "data-changed-notification");
+        addValuesToDataChangedNotificationEventElement(doc, dataChangedNotificationEventElement, change);
+        notificationElement.appendChild(dataChangedNotificationEventElement);
+
+        try {
+            ByteArrayOutputStream out = new ByteArrayOutputStream();
+            TransformerFactory tf = TransformerFactory.newInstance();
+            Transformer transformer = tf.newTransformer();
+            transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
+            transformer.setOutputProperty(OutputKeys.METHOD, "xml");
+            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+            transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
+            transformer.transform(new DOMSource(doc), new StreamResult(new OutputStreamWriter(out, "UTF-8")));
+            byte[] charData = out.toByteArray();
+            return new String(charData, "UTF-8");
+        } catch (TransformerException | UnsupportedEncodingException e) {
+            String msg = "Error during transformation of Document into String";
+            logger.error(msg, e);
+            return msg;
+        }
+    }
+
+    private String toRFC3339(Date d) {
+        return rfc3339.format(d).replaceAll("(\\d\\d)(\\d\\d)$", "$1:$2");
+    }
+
+    private Document createDocument() {
+        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+        Document doc = null;
+        try {
+            DocumentBuilder bob = dbf.newDocumentBuilder();
+            doc = bob.newDocument();
+        } catch (ParserConfigurationException e) {
+            return null;
+        }
+        return doc;
+    }
+
+    private void addValuesToDataChangedNotificationEventElement(Document doc,
+            Element dataChangedNotificationEventElement, DataChangeEvent<InstanceIdentifier, CompositeNode> change) {
+        addValuesFromDataToElement(doc, change.getCreatedConfigurationData(), dataChangedNotificationEventElement, Store.CONFIG, Operation.CREATED);
+        addValuesFromDataToElement(doc, change.getCreatedOperationalData(), dataChangedNotificationEventElement, Store.OPERATION, Operation.CREATED);
+        if (change.getCreatedConfigurationData().isEmpty()) {
+            addValuesFromDataToElement(doc, change.getUpdatedConfigurationData(), dataChangedNotificationEventElement, Store.CONFIG, Operation.UPDATED);
+        }
+        if (change.getCreatedOperationalData().isEmpty()) {
+            addValuesFromDataToElement(doc, change.getUpdatedOperationalData(), dataChangedNotificationEventElement, Store.OPERATION, Operation.UPDATED);
+        }
+        addValuesFromDataToElement(doc, change.getRemovedConfigurationData(), dataChangedNotificationEventElement, Store.CONFIG, Operation.DELETED);
+        addValuesFromDataToElement(doc, change.getRemovedOperationalData(), dataChangedNotificationEventElement, Store.OPERATION, Operation.DELETED);
+    }
+
+    private void addValuesFromDataToElement(Document doc, Set<InstanceIdentifier> data, Element element, Store store,
+            Operation operation) {
+        if (data == null || data.isEmpty()) {
+            return;
+        }
+        for (InstanceIdentifier path : data) {
+            Node node = createDataChangeEventElement(doc, path, null, store, operation);
+            element.appendChild(node);
+        }
+    }
+
+    private void addValuesFromDataToElement(Document doc, Map<InstanceIdentifier, CompositeNode> data, Element element, Store store,
+            Operation operation) {
+        if (data == null || data.isEmpty()) {
+            return;
+        }
+        for (Entry<InstanceIdentifier, CompositeNode> entry : data.entrySet()) {
+            Node node = createDataChangeEventElement(doc, entry.getKey(), entry.getValue(), store, operation);
+            element.appendChild(node);
+        }
+    }
+
+    private Node createDataChangeEventElement(Document doc, InstanceIdentifier path, CompositeNode data, Store store,
+            Operation operation) {
+        Element dataChangeEventElement = doc.createElement("data-change-event");
+
+        Element pathElement = doc.createElement("path");
+        addPathAsValueToElement(path, pathElement);
+        dataChangeEventElement.appendChild(pathElement);
+
+        Element storeElement = doc.createElement("store");
+        storeElement.setTextContent(store.value);
+        dataChangeEventElement.appendChild(storeElement);
+
+        Element operationElement = doc.createElement("operation");
+        operationElement.setTextContent(operation.value);
+        dataChangeEventElement.appendChild(operationElement);
+
+        if (data != null) {
+            Element dataElement = doc.createElement("data");
+            Node dataAnyXml = translateToXml(path, data);
+            Node adoptedNode = doc.adoptNode(dataAnyXml);
+            dataElement.appendChild(adoptedNode);
+            dataChangeEventElement.appendChild(dataElement);
+        }
+
+        return dataChangeEventElement;
+    }
+
+    private Node translateToXml(InstanceIdentifier path, CompositeNode data) {
+        DataNodeContainer schemaNode = ControllerContext.getInstance().getDataNodeContainerFor(path);
+        if (schemaNode == null) {
+            logger.info("Path '{}' contains node with unsupported type (supported type is Container or List) or some node was not found.", path);
+            return null;
+        }
+        try {
+            Document xml = xmlMapper.write(data, schemaNode);
+            return xml.getFirstChild();
+        } catch (UnsupportedDataTypeException e) {
+            logger.error("Error occured during translation of notification to XML.", e);
+            return null;
+        }
+    }
+
+    private void addPathAsValueToElement(InstanceIdentifier path, Element element) {
+        // Map< key = namespace, value = prefix>
+        Map<String, String> prefixes = new HashMap<>();
+        InstanceIdentifier instanceIdentifier = path;
+        StringBuilder textContent = new StringBuilder();
+        for (PathArgument pathArgument : instanceIdentifier.getPath()) {
+            textContent.append("/");
+            writeIdentifierWithNamespacePrefix(element, textContent, pathArgument.getNodeType(), prefixes);
+            if (pathArgument instanceof NodeIdentifierWithPredicates) {
+                Map<QName, Object> predicates = ((NodeIdentifierWithPredicates) pathArgument).getKeyValues();
+                for (QName keyValue : predicates.keySet()) {
+                    String predicateValue = String.valueOf(predicates.get(keyValue));
+                    textContent.append("[");
+                    writeIdentifierWithNamespacePrefix(element, textContent, keyValue, prefixes);
+                    textContent.append("='");
+                    textContent.append(predicateValue);
+                    textContent.append("'");
+                    textContent.append("]");
+                }
+            } else if (pathArgument instanceof NodeWithValue) {
+                textContent.append("[.='");
+                textContent.append(((NodeWithValue)pathArgument).getValue());
+                textContent.append("'");
+                textContent.append("]");
+            }
+        }
+        element.setTextContent(textContent.toString());
+    }
+
+    private static void writeIdentifierWithNamespacePrefix(Element element, StringBuilder textContent, QName qName,
+            Map<String, String> prefixes) {
+        String namespace = qName.getNamespace().toString();
+        String prefix = prefixes.get(namespace);
+        if (prefix == null) {
+            prefix = qName.getPrefix();
+            if (prefix == null || prefix.isEmpty() || prefixes.containsValue(prefix)) {
+                prefix = generateNewPrefix(prefixes.values());
+            }
+        }
+
+        element.setAttribute("xmlns:" + prefix, namespace.toString());
+        textContent.append(prefix);
+        prefixes.put(namespace, prefix);
+
+        textContent.append(":");
+        textContent.append(qName.getLocalName());
+    }
+
+    private static String generateNewPrefix(Collection<String> prefixes) {
+        StringBuilder result = null;
+        Random random = new Random();
+        do {
+            result = new StringBuilder();
+            for (int i = 0; i < 4; i++) {
+                int randomNumber = 0x61 + (Math.abs(random.nextInt()) % 26);
+                result.append(Character.toChars(randomNumber));
+            }
+        } while (prefixes.contains(result.toString()));
+
+        return result.toString();
+    }
+
+    public InstanceIdentifier getPath() {
+        return path;
+    }
+
+    public void setRegistration(ListenerRegistration<DataChangeListener> registration) {
+        this.registration = registration;
+    }
+
+    public String getStreamName() {
+        return streamName;
+    }
+
+    public void close() throws Exception {
+        subscribers = new ConcurrentSet<>();
+        registration.close();
+        registration = null;
+        eventBus.unregister(eventBusChangeRecorder);
+    }
+
+    public boolean isListening() {
+        return registration == null ? false : true;
+    }
+
+    public void addSubscriber(Channel subscriber) {
+        if (!subscriber.isActive()) {
+            logger.debug("Channel is not active between websocket server and subscriber {}"
+                    + subscriber.remoteAddress());
+        }
+        Event event = new Event(EventType.REGISTER);
+        event.setSubscriber(subscriber);
+        eventBus.post(event);
+    }
+
+    public void removeSubscriber(Channel subscriber) {
+        logger.debug("Subscriber {} is removed.", subscriber.remoteAddress());
+        Event event = new Event(EventType.DEREGISTER);
+        event.setSubscriber(subscriber);
+        eventBus.post(event);
+    }
+
+    public boolean hasSubscribers() {
+        return !subscribers.isEmpty();
+    }
+
+    private static enum Store {
+        CONFIG("config"),
+        OPERATION("operation");
+
+        private final String value;
+
+        private Store(String value) {
+            this.value = value;
+        }
+    }
+
+    private static enum Operation {
+        CREATED("created"),
+        UPDATED("updated"),
+        DELETED("deleted");
+
+        private final String value;
+
+        private Operation(String value) {
+            this.value = value;
+        }
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/Notificator.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/Notificator.java
new file mode 100644 (file)
index 0000000..d1cb258
--- /dev/null
@@ -0,0 +1,100 @@
+package org.opendaylight.controller.sal.streams.listeners;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+public class Notificator {
+
+    private static Map<String, ListenerAdapter> listenersByStreamName = new ConcurrentHashMap<>();
+    private static Map<InstanceIdentifier, ListenerAdapter> listenersByInstanceIdentifier = new ConcurrentHashMap<>();
+    private static final Lock lock = new ReentrantLock();
+
+    private Notificator() {
+    }
+
+    public static ListenerAdapter getListenerFor(String streamName) {
+        return listenersByStreamName.get(streamName);
+    }
+
+    public static ListenerAdapter getListenerFor(InstanceIdentifier path) {
+        return listenersByInstanceIdentifier.get(path);
+    }
+
+    public static boolean existListenerFor(InstanceIdentifier path) {
+        return listenersByInstanceIdentifier.containsKey(path);
+    }
+
+    public static ListenerAdapter createListener(InstanceIdentifier path, String streamName) {
+        ListenerAdapter listener = new ListenerAdapter(path, streamName);
+        try {
+            lock.lock();
+            listenersByInstanceIdentifier.put(path, listener);
+            listenersByStreamName.put(streamName, listener);
+        } finally {
+            lock.unlock();
+        }
+        return listener;
+    }
+
+    public static void removeListener(InstanceIdentifier path) {
+        ListenerAdapter listener = listenersByInstanceIdentifier.get(path);
+        deleteListener(listener);
+    }
+
+    public static String createStreamNameFromUri(String uri) {
+        if (uri == null) {
+            return null;
+        }
+        String result = uri;
+        if (result.startsWith("/")) {
+            result = result.substring(1);
+        }
+        if (result.endsWith("/")) {
+            result = result.substring(0, result.length());
+        }
+        return result;
+    }
+
+    public static void removeAllListeners() {
+        for (ListenerAdapter listener : listenersByInstanceIdentifier.values()) {
+            try {
+                listener.close();
+            } catch (Exception e) {
+            }
+        }
+        try {
+            lock.lock();
+            listenersByStreamName = new ConcurrentHashMap<>();
+            listenersByInstanceIdentifier = new ConcurrentHashMap<>();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public static void removeListenerIfNoSubscriberExists(ListenerAdapter listener) {
+        if (!listener.hasSubscribers()) {
+            deleteListener(listener);
+        }
+    }
+
+    private static void deleteListener(ListenerAdapter listener) {
+        if (listener != null) {
+            try {
+                listener.close();
+            } catch (Exception e) {
+            }
+            try {
+                lock.lock();
+                listenersByInstanceIdentifier.remove(listener.getPath());
+                listenersByStreamName.remove(listener.getStreamName());
+            } finally {
+                lock.unlock();
+            }
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServer.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServer.java
new file mode 100644 (file)
index 0000000..142cde1
--- /dev/null
@@ -0,0 +1,52 @@
+package org.opendaylight.controller.sal.streams.websockets;
+
+import org.opendaylight.controller.sal.streams.listeners.Notificator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.Channel;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+
+public class WebSocketServer implements Runnable {
+
+    private static final Logger logger = LoggerFactory.getLogger(WebSocketServer.class);
+
+    public static final int PORT = 8181;
+    private EventLoopGroup bossGroup;
+    private EventLoopGroup workerGroup;
+
+    @Override
+    public void run() {
+        bossGroup = new NioEventLoopGroup();
+        workerGroup = new NioEventLoopGroup();
+        try {
+            ServerBootstrap b = new ServerBootstrap();
+            b.group(bossGroup, workerGroup)
+                .channel(NioServerSocketChannel.class)
+                .childHandler(new WebSocketServerInitializer());
+
+            Channel ch = b.bind(PORT).sync().channel();
+            logger.info("Web socket server started at port {}.", PORT);
+
+            ch.closeFuture().sync();
+        } catch (InterruptedException e) {
+            // NOOP
+        } finally {
+            stop();
+        }
+    }
+
+    private void stop() {
+        Notificator.removeAllListeners();
+        if (bossGroup != null) {
+            bossGroup.shutdownGracefully();
+        }
+        if (workerGroup != null) {
+            workerGroup.shutdownGracefully();
+        }
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServerHandler.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServerHandler.java
new file mode 100644 (file)
index 0000000..618ee57
--- /dev/null
@@ -0,0 +1,134 @@
+package org.opendaylight.controller.sal.streams.websockets;
+
+import static io.netty.handler.codec.http.HttpHeaders.isKeepAlive;
+import static io.netty.handler.codec.http.HttpHeaders.setContentLength;
+import static io.netty.handler.codec.http.HttpHeaders.Names.HOST;
+import static io.netty.handler.codec.http.HttpMethod.GET;
+import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
+import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN;
+import static io.netty.handler.codec.http.HttpResponseStatus.INTERNAL_SERVER_ERROR;
+import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelFutureListener;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.handler.codec.http.DefaultFullHttpResponse;
+import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.FullHttpResponse;
+import io.netty.handler.codec.http.HttpRequest;
+import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.WebSocketFrame;
+import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
+import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;
+import io.netty.util.CharsetUtil;
+
+import java.io.IOException;
+
+import org.opendaylight.controller.sal.streams.listeners.ListenerAdapter;
+import org.opendaylight.controller.sal.streams.listeners.Notificator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object> {
+
+    private static final Logger logger = LoggerFactory.getLogger(WebSocketServerHandler.class);
+
+    private WebSocketServerHandshaker handshaker;
+
+    @Override
+    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
+        if (msg instanceof FullHttpRequest) {
+            handleHttpRequest(ctx, (FullHttpRequest) msg);
+        } else if (msg instanceof WebSocketFrame) {
+            handleWebSocketFrame(ctx, (WebSocketFrame) msg);
+        }
+    }
+
+    private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req)
+            throws Exception {
+        // Handle a bad request.
+        if (!req.getDecoderResult().isSuccess()) {
+            sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, BAD_REQUEST));
+            return;
+        }
+
+        // Allow only GET methods.
+        if (req.getMethod() != GET) {
+            sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN));
+            return;
+        }
+
+        String streamName = Notificator.createStreamNameFromUri(req.getUri());
+        ListenerAdapter listener = Notificator.getListenerFor(streamName);
+        if (listener != null) {
+            listener.addSubscriber(ctx.channel());
+            logger.debug("Subscriber successfully registered.");
+        } else {
+            logger.error("Listener for stream with name '{}' was not found.", streamName);
+            sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, INTERNAL_SERVER_ERROR));
+        }
+
+        // Handshake
+        WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
+                getWebSocketLocation(req), null, false);
+        handshaker = wsFactory.newHandshaker(req);
+        if (handshaker == null) {
+            WebSocketServerHandshakerFactory.sendUnsupportedWebSocketVersionResponse(ctx.channel());
+        } else {
+            handshaker.handshake(ctx.channel(), req);
+        }
+
+    }
+
+    private static void sendHttpResponse(ChannelHandlerContext ctx,
+            HttpRequest req, FullHttpResponse res) {
+        // Generate an error page if response getStatus code is not OK (200).
+        if (res.getStatus().code() != 200) {
+            ByteBuf buf = Unpooled.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8);
+            res.content().writeBytes(buf);
+            buf.release();
+            setContentLength(res, res.content().readableBytes());
+        }
+
+        // Send the response and close the connection if necessary.
+        ChannelFuture f = ctx.channel().writeAndFlush(res);
+        if (!isKeepAlive(req) || res.getStatus().code() != 200) {
+            f.addListener(ChannelFutureListener.CLOSE);
+        }
+    }
+
+    private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) throws IOException {
+        if (frame instanceof CloseWebSocketFrame) {
+            handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain());
+            String streamName = Notificator.createStreamNameFromUri(((CloseWebSocketFrame) frame).reasonText());
+            ListenerAdapter listener = Notificator.getListenerFor(streamName);
+            if (listener != null) {
+                listener.removeSubscriber(ctx.channel());
+                logger.debug("Subscriber successfully registered.");
+            }
+            Notificator.removeListenerIfNoSubscriberExists(listener);
+            return;
+        } else if (frame instanceof PingWebSocketFrame) {
+            ctx.channel().write(new PongWebSocketFrame(frame.content().retain()));
+            return;
+        }
+    }
+
+    @Override
+    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
+            throws Exception {
+        if (cause instanceof java.nio.channels.ClosedChannelException == false) {
+            //cause.printStackTrace();
+        }
+        ctx.close();
+    }
+
+    private static String getWebSocketLocation(HttpRequest req) {
+        return "http://" + req.headers().get(HOST) + req.getUri();
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServerInitializer.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServerInitializer.java
new file mode 100644 (file)
index 0000000..5eb71ef
--- /dev/null
@@ -0,0 +1,19 @@
+package org.opendaylight.controller.sal.streams.websockets;
+
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.HttpServerCodec;
+
+public class WebSocketServerInitializer extends ChannelInitializer<SocketChannel> {
+
+    @Override
+    protected void initChannel(SocketChannel ch) throws Exception {
+        ChannelPipeline pipeline = ch.pipeline();
+        pipeline.addLast("codec-http", new HttpServerCodec());
+        pipeline.addLast("aggregator", new HttpObjectAggregator(65536));
+        pipeline.addLast("handler", new WebSocketServerHandler());
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/iml/varioustests/VariousTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/iml/varioustests/VariousTest.java
deleted file mode 100644 (file)
index cdfed8e..0000000
+++ /dev/null
@@ -1,44 +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.restconf.iml.varioustests;
-
-import org.junit.Ignore;
-import org.junit.Test;
-import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider;
-import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.w3c.dom.Document;
-
-
-public class VariousTest {
-
-    @Ignore
-    @Test
-    public void test() {
-        String[] split = "/something:dfsa/s:sda".split("/");
-        System.out.println(split.length);
-        for (String str : split) {
-            System.out.println(">"+str+"<");    
-        }        
-        
-    }
-    
-    @Test
-    public void loadXml() {
-        TestUtils.readInputToCnSn("/varioustest/xmldata.xml", XmlToCompositeNodeProvider.INSTANCE);
-//        TestUtils.normalizeCompositeNode(compositeNode, modules, schemaNodePath)
-    }
-    
-    @Test
-    public void buildXml() {
-//        Document doc;
-//        doc.createElementNS(namespaceURI, qualifiedName)
-    }
-    
-
-}
index 17d7fe6be09eaa18f48ac5831527fc58076dbe18..dd1502ba79f5c1325aefbeca443fde34e997da90 100644 (file)
@@ -12,12 +12,10 @@ import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
 import java.util.Collections;
-import java.util.Set;
 
 import javax.ws.rs.WebApplicationException;
 
 import org.junit.BeforeClass;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider;
 import org.opendaylight.controller.sal.restconf.impl.test.DummyType;
@@ -29,7 +27,6 @@ import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode;
 import org.opendaylight.yangtools.yang.data.api.MutableSimpleNode;
 import org.opendaylight.yangtools.yang.data.impl.NodeFactory;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.parser.builder.impl.ContainerSchemaNodeBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.impl.LeafSchemaNodeBuilder;
 import org.slf4j.Logger;
@@ -49,7 +46,7 @@ public class CnSnToJsonNotExistingLeafTypeTest extends YangAndXmlAndDataSchemaLo
         String jsonOutput = null;
         jsonOutput = TestUtils
                 .writeCompNodeWithSchemaContextToOutput(prepareCompositeNode(),
-                        (Set<Module>) Collections.EMPTY_SET, prepareDataSchemaNode(),
+                        Collections.EMPTY_SET, prepareDataSchemaNode(),
                         StructuredDataToJsonProvider.INSTANCE);
         assertNotNull(jsonOutput);
         assertTrue(jsonOutput.contains("\"lf1\": \"\""));
index 4218a69d3b9821562b3a38bb7a5a87ac85470e0e..f81c1d63f5af572509a76e2fa5b1da05bafa71bb 100644 (file)
@@ -7,12 +7,10 @@
  */
 package org.opendaylight.controller.sal.restconf.impl.cnsn.to.xml.test;
 
-import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
 import java.util.Collections;
-import java.util.Set;
 
 import javax.ws.rs.WebApplicationException;
 
@@ -21,10 +19,12 @@ import org.junit.Test;
 import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider;
 import org.opendaylight.controller.sal.restconf.impl.test.DummyType;
 import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
-import org.opendaylight.yangtools.yang.data.api.*;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.ModifyAction;
+import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode;
+import org.opendaylight.yangtools.yang.data.api.MutableSimpleNode;
 import org.opendaylight.yangtools.yang.data.impl.NodeFactory;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.parser.builder.impl.ContainerSchemaNodeBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.impl.LeafSchemaNodeBuilder;
 import org.slf4j.Logger;
@@ -41,7 +41,7 @@ public class CnSnToXmlNotExistingLeafTypeTest {
         boolean nullPointerExceptionRaised = false;
         try {
             TestUtils.writeCompNodeWithSchemaContextToOutput(prepareCompositeNode(),
-                    (Set<Module>) Collections.EMPTY_SET, prepareDataSchemaNode(), StructuredDataToXmlProvider.INSTANCE);
+                    Collections.EMPTY_SET, prepareDataSchemaNode(), StructuredDataToXmlProvider.INSTANCE);
         } catch (WebApplicationException | IOException e) {
             LOG.error("WebApplicationException or IOException was raised");
         } catch (NullPointerException e) {
index be7be9444cac594c8080dd99eae2c39ab5baed90..1e01020e78925f6b8b33606da8f43967a584ff12 100644 (file)
@@ -8,6 +8,7 @@
 package org.opendaylight.controller.sal.restconf.impl.test;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
@@ -19,9 +20,12 @@ import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import javax.ws.rs.core.Application;
 import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
 
 import org.glassfish.jersey.server.ResourceConfig;
 import org.glassfish.jersey.test.JerseyTest;
@@ -51,6 +55,9 @@ public class RestGetOperationTest extends JerseyTest {
     private static SchemaContext schemaContextTestModule;
     private static CompositeNode answerFromGet;
 
+    private static SchemaContext schemaContextModules;
+    private static SchemaContext schemaContextBehindMountPoint;
+
     @BeforeClass
     public static void init() throws FileNotFoundException {
         schemaContextYangsIetf = TestUtils.loadSchemaContext("/full-versions/yangs");
@@ -62,15 +69,18 @@ public class RestGetOperationTest extends JerseyTest {
         restconfImpl.setBroker(brokerFacade);
         restconfImpl.setControllerContext(controllerContext);
         answerFromGet = prepareCompositeNodeWithIetfInterfacesInterfacesData();
+
+        schemaContextModules = TestUtils.loadSchemaContext("/modules");
+        schemaContextBehindMountPoint = TestUtils.loadSchemaContext("/modules/modules-behind-mount-point");
     }
 
     @Override
     protected Application configure() {
         /* enable/disable Jersey logs to console */
-//         enable(TestProperties.LOG_TRAFFIC);
-//         enable(TestProperties.DUMP_ENTITY);
-//         enable(TestProperties.RECORD_LOG_LEVEL);
-//         set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue());
+        // enable(TestProperties.LOG_TRAFFIC);
+        // enable(TestProperties.DUMP_ENTITY);
+        // enable(TestProperties.RECORD_LOG_LEVEL);
+        // set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue());
         ResourceConfig resourceConfig = new ResourceConfig();
         resourceConfig = resourceConfig.registerInstances(restconfImpl, StructuredDataToXmlProvider.INSTANCE,
                 StructuredDataToJsonProvider.INSTANCE, XmlToCompositeNodeProvider.INSTANCE,
@@ -118,7 +128,7 @@ public class RestGetOperationTest extends JerseyTest {
         when(mockMountService.getMountPoint(any(InstanceIdentifier.class))).thenReturn(mountInstance);
 
         ControllerContext.getInstance().setMountService(mockMountService);
-        
+
         String uri = createUri("/config/",
                 "ietf-interfaces:interfaces/interface/0/yang-ext:mount/test-module:cont/cont1");
         assertEquals(200, get(uri, MediaType.APPLICATION_XML));
@@ -129,7 +139,8 @@ public class RestGetOperationTest extends JerseyTest {
 
     @Test
     public void getDataMountPointIntoHighestElement() throws UnsupportedEncodingException, URISyntaxException {
-        when(brokerFacade.readConfigurationDataBehindMountPoint(any(MountInstance.class),
+        when(
+                brokerFacade.readConfigurationDataBehindMountPoint(any(MountInstance.class),
                         any(InstanceIdentifier.class))).thenReturn(prepareCnDataForMountPointTest());
         MountInstance mountInstance = mock(MountInstance.class);
         when(mountInstance.getSchemaContext()).thenReturn(schemaContextTestModule);
@@ -138,11 +149,342 @@ public class RestGetOperationTest extends JerseyTest {
 
         ControllerContext.getInstance().setMountService(mockMountService);
 
-        String uri = createUri("/config/",
-                "ietf-interfaces:interfaces/interface/0/yang-ext:mount/");
+        String uri = createUri("/config/", "ietf-interfaces:interfaces/interface/0/yang-ext:mount/");
         assertEquals(200, get(uri, MediaType.APPLICATION_XML));
     }
 
+    // /modules
+    @Test
+    public void getModulesTest() throws UnsupportedEncodingException, FileNotFoundException {
+        ControllerContext.getInstance().setGlobalSchema(schemaContextModules);
+
+        String uri = createUri("/modules", "");
+
+        Response response = target(uri).request("application/yang.api+json").get();
+        validateModulesResponseJson(response);
+
+        response = target(uri).request("application/yang.api+xml").get();
+        validateModulesResponseXml(response);
+    }
+
+    // /modules/module
+    @Test
+    public void getModuleTest() throws FileNotFoundException, UnsupportedEncodingException {
+        ControllerContext.getInstance().setGlobalSchema(schemaContextModules);
+
+        String uri = createUri("/modules/module/module2/2014-01-02", "");
+
+        Response response = target(uri).request("application/yang.api+xml").get();
+        assertEquals(200, response.getStatus());
+        String responseBody = response.readEntity(String.class);
+        assertTrue("Module2 in xml wasn't found", prepareXmlRegex("module2", "2014-01-02", "module:2", responseBody)
+                .find());
+        String[] split = responseBody.split("<module");
+        assertEquals("<module element is returned more then once",2,split.length);
+
+        response = target(uri).request("application/yang.api+json").get();
+        assertEquals(200, response.getStatus());
+        responseBody = response.readEntity(String.class);
+        assertTrue("Module2 in json wasn't found", prepareJsonRegex("module2", "2014-01-02", "module:2", responseBody)
+                .find());
+        split = responseBody.split("\"module\"");
+        assertEquals("\"module\" element is returned more then once",2,split.length);
+
+    }
+
+    // /operations
+    @Test
+    public void getOperationsTest() throws FileNotFoundException, UnsupportedEncodingException {
+        ControllerContext.getInstance().setGlobalSchema(schemaContextModules);
+
+        String uri = createUri("/operations", "");
+
+        Response response = target(uri).request("application/yang.api+xml").get();
+        assertEquals(200, response.getStatus());
+        String responseBody = response.readEntity(String.class);
+        assertTrue("Xml response for /operations dummy-rpc1-module1 is incorrect",
+                validateOperationsResponseXml(responseBody, "dummy-rpc1-module1", "module:1").find());
+        assertTrue("Xml response for /operations dummy-rpc2-module1 is incorrect",
+                validateOperationsResponseXml(responseBody, "dummy-rpc2-module1", "module:1").find());
+        assertTrue("Xml response for /operations dummy-rpc1-module2 is incorrect",
+                validateOperationsResponseXml(responseBody, "dummy-rpc1-module2", "module:2").find());
+        assertTrue("Xml response for /operations dummy-rpc2-module2 is incorrect",
+                validateOperationsResponseXml(responseBody, "dummy-rpc2-module2", "module:2").find());
+
+        response = target(uri).request("application/yang.api+json").get();
+        assertEquals(200, response.getStatus());
+        responseBody = response.readEntity(String.class);
+        assertTrue("Json response for /operations dummy-rpc1-module1 is incorrect",
+                validateOperationsResponseJson(responseBody, "dummy-rpc1-module1", "module1").find());
+        assertTrue("Json response for /operations dummy-rpc2-module1 is incorrect",
+                validateOperationsResponseJson(responseBody, "dummy-rpc2-module1", "module1").find());
+        assertTrue("Json response for /operations dummy-rpc1-module2 is incorrect",
+                validateOperationsResponseJson(responseBody, "dummy-rpc1-module2", "module2").find());
+        assertTrue("Json response for /operations dummy-rpc2-module2 is incorrect",
+                validateOperationsResponseJson(responseBody, "dummy-rpc2-module2", "module2").find());
+
+    }
+
+    // /operations/pathToMountPoint/yang-ext:mount
+    @Test
+    public void getOperationsBehindMountPointTest() throws FileNotFoundException, UnsupportedEncodingException {
+        ControllerContext controllerContext = ControllerContext.getInstance();
+        controllerContext.setGlobalSchema(schemaContextModules);
+
+        MountInstance mountInstance = mock(MountInstance.class);
+        when(mountInstance.getSchemaContext()).thenReturn(schemaContextBehindMountPoint);
+        MountService mockMountService = mock(MountService.class);
+        when(mockMountService.getMountPoint(any(InstanceIdentifier.class))).thenReturn(mountInstance);
+
+        controllerContext.setMountService(mockMountService);
+
+        String uri = createUri("/operations/", "ietf-interfaces:interfaces/interface/0/yang-ext:mount/");
+
+        Response response = target(uri).request("application/yang.api+xml").get();
+        assertEquals(200, response.getStatus());
+        String responseBody = response.readEntity(String.class);
+        assertTrue("Xml response for /operations/mount_point rpc-behind-module1 is incorrect",
+                validateOperationsResponseXml(responseBody, "rpc-behind-module1", "module:1:behind:mount:point").find());
+        assertTrue("Xml response for /operations/mount_point rpc-behind-module2 is incorrect",
+                validateOperationsResponseXml(responseBody, "rpc-behind-module2", "module:2:behind:mount:point").find());
+
+        response = target(uri).request("application/yang.api+json").get();
+        assertEquals(200, response.getStatus());
+        responseBody = response.readEntity(String.class);
+        assertTrue("Json response for /operations/mount_point rpc-behind-module1 is incorrect",
+                validateOperationsResponseJson(responseBody, "rpc-behind-module1", "module1-behind-mount-point").find());
+        assertTrue("Json response for /operations/mount_point rpc-behind-module2 is incorrect",
+                validateOperationsResponseJson(responseBody, "rpc-behind-module2", "module2-behind-mount-point").find());
+
+    }
+
+    private Matcher validateOperationsResponseJson(String searchIn, String rpcName, String moduleName) {
+        StringBuilder regex = new StringBuilder();
+        regex.append("^");
+
+        regex.append(".*\\{");
+        regex.append(".*\"");
+
+        // operations prefix optional
+        regex.append("(");
+        regex.append("ietf-restconf:");
+        regex.append("|)");
+        // :operations prefix optional
+
+        regex.append("operations\"");
+        regex.append(".*:");
+        regex.append(".*\\{");
+
+        regex.append(".*\"" + moduleName);
+        regex.append(":");
+        regex.append(rpcName + "\"");
+        regex.append(".*\\[");
+        regex.append(".*null");
+        regex.append(".*\\]");
+
+        regex.append(".*\\}");
+        regex.append(".*\\}");
+
+        regex.append(".*");
+        regex.append("$");
+        Pattern ptrn = Pattern.compile(regex.toString(), Pattern.DOTALL);
+        return ptrn.matcher(searchIn);
+
+    }
+
+    private Matcher validateOperationsResponseXml(String searchIn, String rpcName, String namespace) {
+        StringBuilder regex = new StringBuilder();
+
+        regex.append("^");
+
+        regex.append(".*<operations");
+        regex.append(".*xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"");
+        regex.append(".*>");
+
+        regex.append(".*<");
+        regex.append(".*" + rpcName);
+        regex.append(".*" + namespace);
+        regex.append(".*/");
+        regex.append(".*>");
+
+        regex.append(".*</operations.*");
+        regex.append(".*>");
+
+        regex.append(".*");
+        regex.append("$");
+        Pattern ptrn = Pattern.compile(regex.toString(), Pattern.DOTALL);
+        return ptrn.matcher(searchIn);
+    }
+
+    // /restconf/modules/pathToMountPoint/yang-ext:mount
+    @Test
+    public void getModulesBehindMountPoint() throws FileNotFoundException, UnsupportedEncodingException {
+        ControllerContext controllerContext = ControllerContext.getInstance();
+        controllerContext.setGlobalSchema(schemaContextModules);
+
+        MountInstance mountInstance = mock(MountInstance.class);
+        when(mountInstance.getSchemaContext()).thenReturn(schemaContextBehindMountPoint);
+        MountService mockMountService = mock(MountService.class);
+        when(mockMountService.getMountPoint(any(InstanceIdentifier.class))).thenReturn(mountInstance);
+
+        controllerContext.setMountService(mockMountService);
+
+        String uri = createUri("/modules/", "ietf-interfaces:interfaces/interface/0/yang-ext:mount/");
+
+        Response response = target(uri).request("application/yang.api+json").get();
+        assertEquals(200, response.getStatus());
+        String responseBody = response.readEntity(String.class);
+
+        assertTrue(
+                "module1-behind-mount-point in json wasn't found",
+                prepareJsonRegex("module1-behind-mount-point", "2014-02-03", "module:1:behind:mount:point",
+                        responseBody).find());
+        assertTrue(
+                "module2-behind-mount-point in json wasn't found",
+                prepareJsonRegex("module2-behind-mount-point", "2014-02-04", "module:2:behind:mount:point",
+                        responseBody).find());
+
+        response = target(uri).request("application/yang.api+xml").get();
+        assertEquals(200, response.getStatus());
+        responseBody = response.readEntity(String.class);
+        assertTrue(
+                "module1-behind-mount-point in json wasn't found",
+                prepareXmlRegex("module1-behind-mount-point", "2014-02-03", "module:1:behind:mount:point", responseBody)
+                        .find());
+        assertTrue(
+                "module2-behind-mount-point in json wasn't found",
+                prepareXmlRegex("module2-behind-mount-point", "2014-02-04", "module:2:behind:mount:point", responseBody)
+                        .find());
+
+    }
+
+    // /restconf/modules/module/pathToMountPoint/yang-ext:mount/moduleName/revision
+    @Test
+    public void getModuleBehindMountPoint() throws FileNotFoundException, UnsupportedEncodingException {
+        ControllerContext controllerContext = ControllerContext.getInstance();
+        controllerContext.setGlobalSchema(schemaContextModules);
+
+        MountInstance mountInstance = mock(MountInstance.class);
+        when(mountInstance.getSchemaContext()).thenReturn(schemaContextBehindMountPoint);
+        MountService mockMountService = mock(MountService.class);
+        when(mockMountService.getMountPoint(any(InstanceIdentifier.class))).thenReturn(mountInstance);
+
+        controllerContext.setMountService(mockMountService);
+
+        String uri = createUri("/modules/module/",
+                "ietf-interfaces:interfaces/interface/0/yang-ext:mount/module1-behind-mount-point/2014-02-03");
+
+        Response response = target(uri).request("application/yang.api+json").get();
+        assertEquals(200, response.getStatus());
+        String responseBody = response.readEntity(String.class);
+
+        assertTrue(
+                "module1-behind-mount-point in json wasn't found",
+                prepareJsonRegex("module1-behind-mount-point", "2014-02-03", "module:1:behind:mount:point",
+                        responseBody).find());
+        String[] split = responseBody.split("\"module\"");
+        assertEquals("\"module\" element is returned more then once",2,split.length);
+
+
+        response = target(uri).request("application/yang.api+xml").get();
+        assertEquals(200, response.getStatus());
+        responseBody = response.readEntity(String.class);
+        assertTrue(
+                "module1-behind-mount-point in json wasn't found",
+                prepareXmlRegex("module1-behind-mount-point", "2014-02-03", "module:1:behind:mount:point", responseBody)
+                        .find());
+        split = responseBody.split("<module");
+        assertEquals("<module element is returned more then once",2,split.length);
+
+
+
+
+    }
+
+    private void validateModulesResponseXml(Response response) {
+        assertEquals(200, response.getStatus());
+        String responseBody = response.readEntity(String.class);
+
+        assertTrue("Module1 in xml wasn't found", prepareXmlRegex("module1", "2014-01-01", "module:1", responseBody)
+                .find());
+        assertTrue("Module2 in xml wasn't found", prepareXmlRegex("module2", "2014-01-02", "module:2", responseBody)
+                .find());
+        assertTrue("Module3 in xml wasn't found", prepareXmlRegex("module3", "2014-01-03", "module:3", responseBody)
+                .find());
+    }
+
+    private void validateModulesResponseJson(Response response) {
+        assertEquals(200, response.getStatus());
+        String responseBody = response.readEntity(String.class);
+
+        assertTrue("Module1 in json wasn't found", prepareJsonRegex("module1", "2014-01-01", "module:1", responseBody)
+                .find());
+        assertTrue("Module2 in json wasn't found", prepareJsonRegex("module2", "2014-01-02", "module:2", responseBody)
+                .find());
+        assertTrue("Module3 in json wasn't found", prepareJsonRegex("module3", "2014-01-03", "module:3", responseBody)
+                .find());
+    }
+
+    private Matcher prepareJsonRegex(String module, String revision, String namespace, String searchIn) {
+        StringBuilder regex = new StringBuilder();
+        regex.append("^");
+
+        regex.append(".*\\{");
+        regex.append(".*\"name\"");
+        regex.append(".*:");
+        regex.append(".*\"" + module + "\",");
+
+        regex.append(".*\"revision\"");
+        regex.append(".*:");
+        regex.append(".*\"" + revision + "\",");
+
+        regex.append(".*\"namespace\"");
+        regex.append(".*:");
+        regex.append(".*\"" + namespace + "\"");
+
+        regex.append(".*\\}");
+
+        regex.append(".*");
+        regex.append("$");
+        Pattern ptrn = Pattern.compile(regex.toString(), Pattern.DOTALL);
+        return ptrn.matcher(searchIn);
+
+    }
+
+    private Matcher prepareXmlRegex(String module, String revision, String namespace, String searchIn) {
+        StringBuilder regex = new StringBuilder();
+        regex.append("^");
+
+        regex.append(".*<module.*");
+        regex.append(".*>");
+
+        regex.append(".*<name>");
+        regex.append(".*" + module);
+        regex.append(".*<\\/name>");
+
+        regex.append(".*<revision>");
+        regex.append(".*" + revision);
+        regex.append(".*<\\/revision>");
+
+        regex.append(".*<namespace>");
+        regex.append(".*" + namespace);
+        regex.append(".*<\\/namespace>");
+
+        regex.append(".*<\\/module.*>");
+
+        regex.append(".*");
+        regex.append("$");
+
+        Pattern ptrn = Pattern.compile(regex.toString(), Pattern.DOTALL);
+        return ptrn.matcher(searchIn);
+    }
+
+    private void prepareMockForModulesTest(ControllerContext mockedControllerContext) throws FileNotFoundException {
+        SchemaContext schemaContext = TestUtils.loadSchemaContext("/modules");
+        mockedControllerContext.setGlobalSchema(schemaContext);
+        // when(mockedControllerContext.getGlobalSchema()).thenReturn(schemaContext);
+    }
+
     private int get(String uri, String mediaType) {
         return target(uri).request(mediaType).get().getStatus();
     }
index 3175ba9821ba45b71a164c53c8f258a955eff7aa..a0e61a6fa12335239ba94efd386e841eda745d1c 100644 (file)
@@ -15,13 +15,13 @@ import com.google.common.base.Charsets;
 
 public class RestOperationUtils {
 
-    static final String JSON = "+json";
-    static final String XML = "+xml";
+    public static final String JSON = "+json";
+    public static final String XML = "+xml";
 
     private RestOperationUtils() {
     }
 
-    static String createUri(String prefix, String encodedPart) throws UnsupportedEncodingException {
+    public static String createUri(String prefix, String encodedPart) throws UnsupportedEncodingException {
         return URI.create(prefix + URLEncoder.encode(encodedPart, Charsets.US_ASCII.name()).toString()).toASCIIString();
     }
 }
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/IClientMessageCallback.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/IClientMessageCallback.java
new file mode 100644 (file)
index 0000000..63b8e6b
--- /dev/null
@@ -0,0 +1,9 @@
+package org.opendaylight.controller.sal.restconf.impl.websockets.client;
+
+/**
+ * Created by mbobak on 1/22/14.
+ */
+public interface IClientMessageCallback {
+
+    public void onMessageReceived(Object message);
+}
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/WebSocketClient.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/WebSocketClient.java
new file mode 100644 (file)
index 0000000..845d54e
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * 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.restconf.impl.websockets.client;
+
+import io.netty.bootstrap.Bootstrap;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import io.netty.handler.codec.http.HttpClientCodec;
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
+import io.netty.handler.codec.http.websocketx.WebSocketVersion;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.net.URI;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class WebSocketClient  {
+
+    private final URI uri;
+    private Bootstrap bootstrap = new Bootstrap();;
+    private final WebSocketClientHandler clientHandler;
+    private static final Logger logger = LoggerFactory.getLogger(WebSocketClient.class);
+    private Channel clientChannel;
+    private final EventLoopGroup group = new NioEventLoopGroup();
+
+    public WebSocketClient(URI uri,IClientMessageCallback clientMessageCallback) {
+        this.uri = uri;
+        clientHandler = new WebSocketClientHandler(
+                WebSocketClientHandshakerFactory.newHandshaker(
+                        uri, WebSocketVersion.V13, null, false,null),clientMessageCallback); // last null could be replaced with DefaultHttpHeaders
+        initialize();
+    }
+    private void initialize(){
+
+        String protocol = uri.getScheme();
+        if (!"http".equals(protocol)) {
+            throw new IllegalArgumentException("Unsupported protocol: " + protocol);
+        }
+
+        bootstrap.group(group)
+                .channel(NioSocketChannel.class)
+                .handler(new ChannelInitializer<SocketChannel>() {
+                    @Override
+                    public void initChannel(SocketChannel ch) throws Exception {
+                        ChannelPipeline pipeline = ch.pipeline();
+                        pipeline.addLast("http-codec", new HttpClientCodec());
+                        pipeline.addLast("aggregator", new HttpObjectAggregator(8192));
+                        pipeline.addLast("ws-handler", clientHandler);
+                    }
+                });
+    }
+    public void connect() throws InterruptedException{
+        System.out.println("WebSocket Client connecting");
+        clientChannel  = bootstrap.connect(uri.getHost(), uri.getPort()).sync().channel();
+        clientHandler.handshakeFuture().sync();
+    }
+
+    public void writeAndFlush(String message){
+        clientChannel.writeAndFlush(new TextWebSocketFrame(message));
+    }
+    public void writeAndFlush(Object message){
+        clientChannel.writeAndFlush(message);
+    }
+
+    public void ping(){
+        clientChannel.writeAndFlush(new PingWebSocketFrame(Unpooled.copiedBuffer(new byte[]{1, 2, 3, 4, 5, 6})));
+    }
+
+    public void close(String reasonText) throws InterruptedException {
+        CloseWebSocketFrame closeWebSocketFrame = new CloseWebSocketFrame(1000,reasonText);
+        clientChannel.writeAndFlush(closeWebSocketFrame);
+
+        // WebSocketClientHandler will close the connection when the server
+        // responds to the CloseWebSocketFrame.
+        clientChannel.closeFuture().sync();
+        group.shutdownGracefully();
+    }
+
+    public static void main(String[] args) throws Exception {
+        URI uri;
+        if (args.length > 0) {
+            uri = new URI(args[0]);
+        } else {
+            uri = new URI("http://192.168.1.101:8181/opendaylight-inventory:nodes");
+        }
+        IClientMessageCallback messageCallback = new ClientMessageCallback();
+        WebSocketClient webSocketClient = new WebSocketClient(uri, messageCallback);
+        webSocketClient.connect();
+
+        while (true) {
+            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
+            String input = br.readLine();
+            if (input.equals("q")) {
+                System.out.print("Would you like to close stream? (Y = yes, empty = yes)\n");
+                input = br.readLine();
+                if (input.equals("yes") || input.isEmpty()) {
+                    webSocketClient.close("opendaylight-inventory:nodes");
+                    break;
+                }
+            }
+        }
+    }
+
+    private static class ClientMessageCallback implements IClientMessageCallback {
+        @Override
+        public void onMessageReceived(Object message) {
+            if (message instanceof TextWebSocketFrame) {
+                logger.info("received message {}"+ ((TextWebSocketFrame)message).text());
+            }
+        }
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/WebSocketClientHandler.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/WebSocketClientHandler.java
new file mode 100644 (file)
index 0000000..0a16e25
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * 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.restconf.impl.websockets.client;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelPromise;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.handler.codec.http.FullHttpResponse;
+import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
+import io.netty.handler.codec.http.websocketx.WebSocketFrame;
+import io.netty.util.CharsetUtil;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class WebSocketClientHandler extends SimpleChannelInboundHandler<Object> {
+
+    private static final Logger logger = LoggerFactory.getLogger(WebSocketClientHandler.class.toString());
+    private final WebSocketClientHandshaker handshaker;
+    private ChannelPromise handshakeFuture;
+    private final IClientMessageCallback messageListener;
+
+
+    public WebSocketClientHandler(WebSocketClientHandshaker handshaker,IClientMessageCallback listener) {
+        this.handshaker = handshaker;
+        this.messageListener = listener;
+    }
+
+    public ChannelFuture handshakeFuture() {
+        return handshakeFuture;
+    }
+
+    @Override
+    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
+        handshakeFuture = ctx.newPromise();
+    }
+
+    @Override
+    public void channelActive(ChannelHandlerContext ctx) throws Exception {
+        handshaker.handshake(ctx.channel());
+    }
+
+    @Override
+    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
+        logger.info("WebSocket Client disconnected!");
+    }
+
+    @Override
+    public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
+        Channel ch = ctx.channel();
+        if (!handshaker.isHandshakeComplete()) {
+            handshaker.finishHandshake(ch, (FullHttpResponse) msg);
+            logger.info("WebSocket Client connected!");
+            handshakeFuture.setSuccess();
+            return;
+        }
+
+        if (msg instanceof FullHttpResponse) {
+            FullHttpResponse response = (FullHttpResponse) msg;
+            throw new Exception("Unexpected FullHttpResponse (getStatus=" + response.getStatus() + ", content="
+                    + response.content().toString(CharsetUtil.UTF_8) + ')');
+        }
+
+        messageListener.onMessageReceived(msg);
+        WebSocketFrame frame = (WebSocketFrame) msg;
+
+        if (frame instanceof PongWebSocketFrame) {
+            logger.info("WebSocket Client received pong");
+        } else if (frame instanceof CloseWebSocketFrame) {
+            logger.info("WebSocket Client received closing");
+            ch.close();
+        }
+    }
+
+    @Override
+    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+        cause.printStackTrace();
+
+        if (!handshakeFuture.isDone()) {
+            handshakeFuture.setFailure(cause);
+        }
+
+        ctx.close();
+    }
+}
+
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/test/RestStream.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/test/RestStream.java
new file mode 100644 (file)
index 0000000..4dcc63e
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.websockets.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.opendaylight.controller.sal.restconf.impl.test.RestOperationUtils.createUri;
+
+import java.io.FileNotFoundException;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.sal.rest.impl.JsonToCompositeNodeProvider;
+import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider;
+import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider;
+import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider;
+import org.opendaylight.controller.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
+import org.opendaylight.controller.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public class RestStream extends JerseyTest {
+
+    private static BrokerFacade brokerFacade;
+    private static RestconfImpl restconfImpl;
+    private static SchemaContext schemaContextYangsIetf;
+
+    @BeforeClass
+    public static void init() throws FileNotFoundException {
+        schemaContextYangsIetf = TestUtils.loadSchemaContext("/full-versions/yangs");
+        ControllerContext controllerContext = ControllerContext.getInstance();
+        controllerContext.setSchemas(schemaContextYangsIetf);
+        brokerFacade = mock(BrokerFacade.class);
+        restconfImpl = RestconfImpl.getInstance();
+        restconfImpl.setBroker(brokerFacade);
+        restconfImpl.setControllerContext(controllerContext);
+    }
+
+    @Override
+    protected Application configure() {
+        /* enable/disable Jersey logs to console */
+//         enable(TestProperties.LOG_TRAFFIC);
+//         enable(TestProperties.DUMP_ENTITY);
+//         enable(TestProperties.RECORD_LOG_LEVEL);
+//         set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue());
+        ResourceConfig resourceConfig = new ResourceConfig();
+        resourceConfig = resourceConfig.registerInstances(restconfImpl, StructuredDataToXmlProvider.INSTANCE,
+                StructuredDataToJsonProvider.INSTANCE, XmlToCompositeNodeProvider.INSTANCE,
+                JsonToCompositeNodeProvider.INSTANCE);
+        return resourceConfig;
+    }
+
+    @Test
+    public void testCallRpcCallGet() throws UnsupportedEncodingException, InterruptedException {
+        String uri = createUri("/operations/", "sal-remote:create-data-change-event-subscription");
+        Response responseWithStreamName = post(uri, MediaType.APPLICATION_XML, getRpcInput());
+        String xmlResponse = responseWithStreamName.readEntity(String.class);
+        assertNotNull(xmlResponse);
+        assertTrue(xmlResponse.contains("<stream-name>ietf-interfaces:interfaces/ietf-interfaces:interface/eth0</stream-name>"));
+
+        uri = createUri("/streams/stream/", "ietf-interfaces:interfaces/ietf-interfaces:interface/eth0");
+        Response responseWithRedirectionUri = get(uri, MediaType.APPLICATION_XML);
+        final URI websocketServerUri = responseWithRedirectionUri.getLocation();
+        assertNotNull(websocketServerUri);
+        assertEquals(websocketServerUri.toString(), "http://localhost:8181/ietf-interfaces:interfaces/ietf-interfaces:interface/eth0");
+    }
+
+    private Response post(String uri, String mediaType, String data) {
+        return target(uri).request(mediaType).post(Entity.entity(data, mediaType));
+    }
+
+    private Response get(String uri, String mediaType) {
+        return target(uri).request(mediaType).get();
+    }
+
+    private String getRpcInput() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("<input xmlns=\"urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote\">");
+        sb.append("<path xmlns:int=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">/int:interfaces/int:interface[int:name='eth0']</path>");
+        sb.append("</input>");
+        return sb.toString();
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/full-versions/yangs/sal-remote@2014-01-14.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/full-versions/yangs/sal-remote@2014-01-14.yang
new file mode 100644 (file)
index 0000000..d12e252
--- /dev/null
@@ -0,0 +1,98 @@
+module sal-remote {
+
+       yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote";
+    prefix "sal-remote";
+    
+
+    organization "Cisco Systems, Inc.";
+    contact "Martin Bobak <mbobak@cisco.com>";
+
+    description
+          "This module contains the definition of methods related to
+           sal remote model.
+
+           Copyright (c)2013 Cisco Systems, Inc. All rights reserved.
+
+           This program and the accompanying materials are made available
+           under the terms of the Eclipse Public License v1.0 which
+           accompanies this distribution, and is available at
+           http://www.eclipse.org/legal/epl-v10.html";
+
+    revision "2014-01-14" {
+        description
+            "Initial revision";
+    }
+
+
+     typedef q-name {
+       type string;
+       reference
+         "http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#QName";
+     }
+
+    rpc create-data-change-event-subscription {
+        input {
+            leaf path {
+                type instance-identifier;
+                description "Subtree path. ";
+            }
+         }
+         output {
+            leaf stream-name {
+                type string;
+                description "Notification stream name.";
+            }
+         }
+    }
+
+    notification data-changed-notification {
+        description "Data change notification.";
+        list data-change-event {
+            key path;
+            leaf path {
+                type instance-identifier;
+            }
+            leaf store {
+                type enumeration {
+                    enum config;
+                    enum operation;
+                }
+            }
+            leaf operation {
+                type enumeration {
+                    enum created;
+                    enum updated;
+                    enum deleted;
+                }
+            }
+            anyxml data{
+                description "DataObject ";
+            }
+         }
+    }
+
+    rpc create-notification-stream {
+        input {
+            leaf-list notifications {
+                type q-name;
+                description "Notification QNames";
+            }
+         }
+        output {
+            leaf notification-stream-identifier {
+                type string;
+                description "Unique notification stream identifier, in which notifications will be propagated";
+            }
+        }
+    }
+
+    rpc begin-transaction{
+        output{
+            anyxml data-modification-transaction{
+                description "DataModificationTransaction xml";
+            }
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/iana-if-type.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/iana-if-type.yang
new file mode 100644 (file)
index 0000000..7bd0003
--- /dev/null
@@ -0,0 +1,1517 @@
+module iana-if-type {
+  namespace "urn:ietf:params:xml:ns:yang:iana-if-type";
+  prefix ianaift;
+
+  organization "IANA";
+  contact
+    "        Internet Assigned Numbers Authority
+
+     Postal: ICANN
+             4676 Admiralty Way, Suite 330
+             Marina del Rey, CA 90292
+
+     Tel:    +1 310 823 9358
+     E-Mail: iana&iana.org";
+  description
+    "This YANG module defines the iana-if-type typedef, which
+     contains YANG definitions for IANA-registered interface types.
+
+     This YANG module is maintained by IANA, and reflects the
+     'ifType definitions' registry.
+
+     The latest revision of this YANG module can be obtained from
+     the IANA web site.
+
+     Copyright (c) 2011 IETF Trust and the persons identified as
+     authors of the code.  All rights reserved.
+
+     Redistribution and use in source and binary forms, with or
+     without modification, is permitted pursuant to, and subject
+     to the license terms contained in, the Simplified BSD License
+     set forth in Section 4.c of the IETF Trust's Legal Provisions
+     Relating to IETF Documents
+     (http://trustee.ietf.org/license-info).
+
+     This version of this YANG module is part of RFC XXXX; see
+     the RFC itself for full legal notices.";
+  // RFC Ed.: replace XXXX with actual RFC number and remove this
+  // note.
+
+  // RFC Ed.: update the date below with the date of RFC publication
+  // and remove this note.
+  revision 2013-07-04 {
+    description
+      "Initial revision.";
+    reference
+      "RFC XXXX: IANA Interface Type YANG Module";
+  }
+
+  typedef iana-if-type {
+    type enumeration {
+      enum "other" {
+        value 1;
+        description
+          "None of the following";
+      }
+      enum "regular1822" {
+        value 2;
+      }
+      enum "hdh1822" {
+        value 3;
+      }
+      enum "ddnX25" {
+        value 4;
+      }
+      enum "rfc877x25" {
+        value 5;
+        reference
+          "RFC 1382 - SNMP MIB Extension for the X.25 Packet Layer";
+      }
+      enum "ethernetCsmacd" {
+        value 6;
+        description
+          "For all ethernet-like interfaces, regardless of speed,
+           as per RFC3635.";
+        reference
+          "RFC 3635 - Definitions of Managed Objects for the
+                      Ethernet-like Interface Types.";
+      }
+      enum "iso88023Csmacd" {
+        value 7;
+        status deprecated;
+        description
+          "Deprecated via RFC3635.
+           Use ethernetCsmacd(6) instead.";
+        reference
+          "RFC 3635 - Definitions of Managed Objects for the
+                      Ethernet-like Interface Types.";
+      }
+      enum "iso88024TokenBus" {
+        value 8;
+      }
+      enum "iso88025TokenRing" {
+        value 9;
+      }
+      enum "iso88026Man" {
+        value 10;
+      }
+      enum "starLan" {
+        value 11;
+        status deprecated;
+        description
+          "Deprecated via RFC3635.
+           Use ethernetCsmacd(6) instead.";
+        reference
+          "RFC 3635 - Definitions of Managed Objects for the
+                      Ethernet-like Interface Types.";
+      }
+      enum "proteon10Mbit" {
+        value 12;
+      }
+      enum "proteon80Mbit" {
+        value 13;
+      }
+      enum "hyperchannel" {
+        value 14;
+      }
+      enum "fddi" {
+        value 15;
+        reference
+          "RFC 1512 - FDDI Management Information Base";
+      }
+      enum "lapb" {
+        value 16;
+        reference
+          "RFC 1381 - SNMP MIB Extension for X.25 LAPB";
+      }
+      enum "sdlc" {
+        value 17;
+      }
+      enum "ds1" {
+        value 18;
+        description
+          "DS1-MIB";
+        reference
+          "RFC 4805 - Definitions of Managed Objects for the
+                      DS1, J1, E1, DS2, and E2 Interface Types";
+      }
+      enum "e1" {
+        value 19;
+        status obsolete;
+        description
+          "Obsolete see DS1-MIB";
+        reference
+          "RFC 4805 - Definitions of Managed Objects for the
+                      DS1, J1, E1, DS2, and E2 Interface Types";
+      }
+      enum "basicISDN" {
+        value 20;
+        description
+          "see also RFC2127";
+      }
+      enum "primaryISDN" {
+        value 21;
+      }
+      enum "propPointToPointSerial" {
+        value 22;
+        description
+          "proprietary serial";
+      }
+      enum "ppp" {
+        value 23;
+      }
+      enum "softwareLoopback" {
+        value 24;
+      }
+      enum "eon" {
+        value 25;
+        description
+          "CLNP over IP";
+      }
+      enum "ethernet3Mbit" {
+        value 26;
+      }
+      enum "nsip" {
+        value 27;
+        description
+          "XNS over IP";
+      }
+      enum "slip" {
+        value 28;
+        description
+          "generic SLIP";
+      }
+      enum "ultra" {
+        value 29;
+        description
+          "ULTRA technologies";
+      }
+      enum "ds3" {
+        value 30;
+        description
+          "DS3-MIB";
+        reference
+          "RFC 3896 - Definitions of Managed Objects for the
+                      DS3/E3 Interface Type";
+      }
+      enum "sip" {
+        value 31;
+        description
+          "SMDS, coffee";
+        reference
+          "RFC 1694 - Definitions of Managed Objects for SMDS
+                      Interfaces using SMIv2";
+      }
+      enum "frameRelay" {
+        value 32;
+        description
+          "DTE only.";
+        reference
+          "RFC 2115 - Management Information Base for Frame Relay
+                      DTEs Using SMIv2";
+      }
+      enum "rs232" {
+        value 33;
+        reference
+          "RFC 1659 - Definitions of Managed Objects for RS-232-like
+                      Hardware Devices using SMIv2";
+      }
+      enum "para" {
+        value 34;
+        description
+          "parallel-port";
+        reference
+          "RFC 1660 - Definitions of Managed Objects for
+                      Parallel-printer-like Hardware Devices using
+                      SMIv2";
+      }
+      enum "arcnet" {
+        value 35;
+        description
+          "arcnet";
+      }
+      enum "arcnetPlus" {
+        value 36;
+        description
+          "arcnet plus";
+      }
+      enum "atm" {
+        value 37;
+        description
+          "ATM cells";
+      }
+      enum "miox25" {
+        value 38;
+        reference
+          "RFC 1461 - SNMP MIB extension for Multiprotocol
+                      Interconnect over X.25";
+      }
+      enum "sonet" {
+        value 39;
+        description
+          "SONET or SDH";
+      }
+      enum "x25ple" {
+        value 40;
+        reference
+          "RFC 2127 - ISDN Management Information Base using SMIv2";
+      }
+      enum "iso88022llc" {
+        value 41;
+      }
+      enum "localTalk" {
+        value 42;
+      }
+      enum "smdsDxi" {
+        value 43;
+      }
+      enum "frameRelayService" {
+        value 44;
+        description
+          "FRNETSERV-MIB";
+        reference
+          "RFC 2954 - Definitions of Managed Objects for Frame
+                      Relay Service";
+      }
+      enum "v35" {
+        value 45;
+      }
+      enum "hssi" {
+        value 46;
+      }
+      enum "hippi" {
+        value 47;
+      }
+      enum "modem" {
+        value 48;
+        description
+          "Generic modem";
+      }
+      enum "aal5" {
+        value 49;
+        description
+          "AAL5 over ATM";
+      }
+      enum "sonetPath" {
+        value 50;
+      }
+      enum "sonetVT" {
+        value 51;
+      }
+      enum "smdsIcip" {
+        value 52;
+        description
+          "SMDS InterCarrier Interface";
+      }
+      enum "propVirtual" {
+        value 53;
+        description
+          "proprietary virtual/internal";
+        reference
+          "RFC 2863 - The Interfaces Group MIB";
+      }
+      enum "propMultiplexor" {
+        value 54;
+        description
+          "proprietary multiplexing";
+        reference
+          "RFC 2863 - The Interfaces Group MIB";
+      }
+      enum "ieee80212" {
+        value 55;
+        description
+          "100BaseVG";
+      }
+      enum "fibreChannel" {
+        value 56;
+        description
+          "Fibre Channel";
+      }
+      enum "hippiInterface" {
+        value 57;
+        description
+          "HIPPI interfaces";
+      }
+      enum "frameRelayInterconnect" {
+        value 58;
+        status obsolete;
+        description
+          "Obsolete use either
+           frameRelay(32) or frameRelayService(44).";
+      }
+      enum "aflane8023" {
+        value 59;
+        description
+          "ATM Emulated LAN for 802.3";
+      }
+      enum "aflane8025" {
+        value 60;
+        description
+          "ATM Emulated LAN for 802.5";
+      }
+      enum "cctEmul" {
+        value 61;
+        description
+         "ATM Emulated circuit";
+      }
+      enum "fastEther" {
+        value 62;
+        status deprecated;
+        description
+          "Obsoleted via RFC3635.
+          ethernetCsmacd(6) should be used instead";
+        reference
+          "RFC 3635 - Definitions of Managed Objects for the
+                      Ethernet-like Interface Types.";
+      }
+      enum "isdn" {
+        value 63;
+        description
+          "ISDN and X.25";
+        reference
+          "RFC 1356 - Multiprotocol Interconnect on X.25 and ISDN
+                      in the Packet Mode";
+      }
+      enum "v11" {
+        value 64;
+        description
+         "CCITT V.11/X.21";
+      }
+      enum "v36" {
+        value 65;
+        description
+          "CCITT V.36";
+      }
+      enum "g703at64k" {
+        value 66;
+        description
+          "CCITT G703 at 64Kbps";
+      }
+      enum "g703at2mb" {
+        value 67;
+        status obsolete;
+        description
+          "Obsolete see DS1-MIB";
+      }
+      enum "qllc" {
+        value 68;
+        description
+          "SNA QLLC";
+      }
+      enum "fastEtherFX" {
+        value 69;
+        status deprecated;
+        description
+          "Obsoleted via RFC3635
+          ethernetCsmacd(6) should be used instead";
+        reference
+          "RFC 3635 - Definitions of Managed Objects for the
+                      Ethernet-like Interface Types.";
+      }
+      enum "channel" {
+        value 70;
+        description
+          "channel";
+      }
+      enum "ieee80211" {
+        value 71;
+        description
+          "radio spread spectrum";
+      }
+      enum "ibm370parChan" {
+        value 72;
+        description
+          "IBM System 360/370 OEMI Channel";
+      }
+      enum "escon" {
+        value 73;
+        description
+          "IBM Enterprise Systems Connection";
+      }
+      enum "dlsw" {
+        value 74;
+        description
+          "Data Link Switching";
+      }
+      enum "isdns" {
+        value 75;
+        description
+          "ISDN S/T interface";
+      }
+      enum "isdnu" {
+        value 76;
+        description
+          "ISDN U interface";
+      }
+      enum "lapd" {
+        value 77;
+        description
+          "Link Access Protocol D";
+      }
+      enum "ipSwitch" {
+        value 78;
+        description
+          "IP Switching Objects";
+      }
+      enum "rsrb" {
+        value 79;
+        description
+          "Remote Source Route Bridging";
+      }
+      enum "atmLogical" {
+        value 80;
+        description
+          "ATM Logical Port";
+        reference
+          "RFC 3606 - Definitions of Supplemental Managed Objects
+                      for ATM Interface";
+      }
+      enum "ds0" {
+        value 81;
+        description
+          "Digital Signal Level 0";
+        reference
+          "RFC 2494 - Definitions of Managed Objects for the DS0
+                      and DS0 Bundle Interface Type";
+      }
+      enum "ds0Bundle" {
+        value 82;
+        description
+          "group of ds0s on the same ds1";
+        reference
+          "RFC 2494 - Definitions of Managed Objects for the DS0
+                      and DS0 Bundle Interface Type";
+      }
+      enum "bsc" {
+        value 83;
+        description
+          "Bisynchronous Protocol";
+      }
+      enum "async" {
+        value 84;
+        description
+          "Asynchronous Protocol";
+      }
+      enum "cnr" {
+        value 85;
+        description
+          "Combat Net Radio";
+      }
+      enum "iso88025Dtr" {
+        value 86;
+        description
+          "ISO 802.5r DTR";
+      }
+      enum "eplrs" {
+        value 87;
+        description
+          "Ext Pos Loc Report Sys";
+      }
+      enum "arap" {
+        value 88;
+        description
+          "Appletalk Remote Access Protocol";
+      }
+      enum "propCnls" {
+        value 89;
+        description
+          "Proprietary Connectionless Protocol";
+      }
+      enum "hostPad" {
+        value 90;
+        description
+          "CCITT-ITU X.29 PAD Protocol";
+      }
+      enum "termPad" {
+        value 91;
+        description
+          "CCITT-ITU X.3 PAD Facility";
+      }
+      enum "frameRelayMPI" {
+        value 92;
+        description
+          "Multiproto Interconnect over FR";
+      }
+      enum "x213" {
+        value 93;
+        description
+          "CCITT-ITU X213";
+      }
+      enum "adsl" {
+        value 94;
+        description
+          "Asymmetric Digital Subscriber Loop";
+      }
+      enum "radsl" {
+        value 95;
+        description
+          "Rate-Adapt. Digital Subscriber Loop";
+      }
+      enum "sdsl" {
+        value 96;
+        description
+          "Symmetric Digital Subscriber Loop";
+      }
+      enum "vdsl" {
+        value 97;
+        description
+          "Very H-Speed Digital Subscrib. Loop";
+      }
+      enum "iso88025CRFPInt" {
+        value 98;
+        description
+          "ISO 802.5 CRFP";
+      }
+      enum "myrinet" {
+        value 99;
+        description
+          "Myricom Myrinet";
+      }
+      enum "voiceEM" {
+        value 100;
+        description
+          "voice recEive and transMit";
+      }
+      enum "voiceFXO" {
+        value 101;
+        description
+          "voice Foreign Exchange Office";
+      }
+      enum "voiceFXS" {
+        value 102;
+        description
+          "voice Foreign Exchange Station";
+      }
+      enum "voiceEncap" {
+        value 103;
+        description
+          "voice encapsulation";
+      }
+      enum "voiceOverIp" {
+        value 104;
+        description
+          "voice over IP encapsulation";
+      }
+      enum "atmDxi" {
+        value 105;
+        description
+          "ATM DXI";
+      }
+      enum "atmFuni" {
+        value 106;
+        description
+          "ATM FUNI";
+      }
+      enum "atmIma" {
+        value 107;
+        description
+          "ATM IMA";
+      }
+      enum "pppMultilinkBundle" {
+        value 108;
+        description
+          "PPP Multilink Bundle";
+      }
+      enum "ipOverCdlc" {
+        value 109;
+        description
+          "IBM ipOverCdlc";
+      }
+      enum "ipOverClaw" {
+        value 110;
+        description
+          "IBM Common Link Access to Workstn";
+      }
+      enum "stackToStack" {
+        value 111;
+        description
+          "IBM stackToStack";
+      }
+      enum "virtualIpAddress" {
+        value 112;
+        description
+          "IBM VIPA";
+      }
+      enum "mpc" {
+        value 113;
+        description
+          "IBM multi-protocol channel support";
+      }
+      enum "ipOverAtm" {
+        value 114;
+        description
+          "IBM ipOverAtm";
+        reference
+          "RFC 2320 - Definitions of Managed Objects for Classical IP
+                      and ARP Over ATM Using SMIv2 (IPOA-MIB)";
+      }
+      enum "iso88025Fiber" {
+        value 115;
+        description
+          "ISO 802.5j Fiber Token Ring";
+      }
+      enum "tdlc" {
+        value 116;
+        description
+          "IBM twinaxial data link control";
+      }
+      enum "gigabitEthernet" {
+        value 117;
+        status deprecated;
+        description
+          "Obsoleted via RFC3635
+           ethernetCsmacd(6) should be used instead";
+        reference
+          "RFC 3635 - Definitions of Managed Objects for the
+                      Ethernet-like Interface Types.";
+      }
+      enum "hdlc" {
+        value 118;
+        description
+          "HDLC";
+      }
+      enum "lapf" {
+        value 119;
+        description
+          "LAP F";
+      }
+      enum "v37" {
+        value 120;
+        description
+          "V.37";
+      }
+      enum "x25mlp" {
+        value 121;
+        description
+          "Multi-Link Protocol";
+      }
+      enum "x25huntGroup" {
+        value 122;
+        description
+          "X25 Hunt Group";
+      }
+      enum "transpHdlc" {
+        value 123;
+        description
+          "Transp HDLC";
+      }
+      enum "interleave" {
+        value 124;
+        description
+          "Interleave channel";
+      }
+      enum "fast" {
+        value 125;
+        description
+          "Fast channel";
+      }
+      enum "ip" {
+        value 126;
+        description
+          "IP (for APPN HPR in IP networks)";
+      }
+      enum "docsCableMaclayer" {
+        value 127;
+        description
+          "CATV Mac Layer";
+      }
+      enum "docsCableDownstream" {
+        value 128;
+        description
+          "CATV Downstream interface";
+      }
+      enum "docsCableUpstream" {
+        value 129;
+        description
+          "CATV Upstream interface";
+      }
+      enum "a12MppSwitch" {
+        value 130;
+        description
+          "Avalon Parallel Processor";
+      }
+      enum "tunnel" {
+        value 131;
+        description
+          "Encapsulation interface";
+      }
+      enum "coffee" {
+        value 132;
+        description
+          "coffee pot";
+        reference
+          "RFC 2325 - Coffee MIB";
+      }
+      enum "ces" {
+        value 133;
+        description
+          "Circuit Emulation Service";
+      }
+      enum "atmSubInterface" {
+        value 134;
+        description
+          "ATM Sub Interface";
+      }
+      enum "l2vlan" {
+        value 135;
+        description
+          "Layer 2 Virtual LAN using 802.1Q";
+      }
+      enum "l3ipvlan" {
+        value 136;
+        description
+          "Layer 3 Virtual LAN using IP";
+      }
+      enum "l3ipxvlan" {
+        value 137;
+        description
+          "Layer 3 Virtual LAN using IPX";
+      }
+      enum "digitalPowerline" {
+        value 138;
+        description
+          "IP over Power Lines";
+      }
+      enum "mediaMailOverIp" {
+        value 139;
+        description
+          "Multimedia Mail over IP";
+      }
+      enum "dtm" {
+        value 140;
+        description
+          "Dynamic syncronous Transfer Mode";
+      }
+      enum "dcn" {
+        value 141;
+        description
+          "Data Communications Network";
+      }
+      enum "ipForward" {
+        value 142;
+        description
+          "IP Forwarding Interface";
+      }
+      enum "msdsl" {
+        value 143;
+        description
+          "Multi-rate Symmetric DSL";
+      }
+      enum "ieee1394" {
+        value 144;
+        description
+          "IEEE1394 High Performance Serial Bus";
+      }
+      enum "if-gsn" {
+        value 145;
+        description
+          "HIPPI-6400";
+      }
+      enum "dvbRccMacLayer" {
+        value 146;
+        description
+          "DVB-RCC MAC Layer";
+      }
+      enum "dvbRccDownstream" {
+        value 147;
+        description
+          "DVB-RCC Downstream Channel";
+      }
+      enum "dvbRccUpstream" {
+        value 148;
+        description
+          "DVB-RCC Upstream Channel";
+      }
+      enum "atmVirtual" {
+        value 149;
+        description
+          "ATM Virtual Interface";
+      }
+      enum "mplsTunnel" {
+        value 150;
+        description
+          "MPLS Tunnel Virtual Interface";
+      }
+      enum "srp" {
+        value 151;
+        description
+          "Spatial Reuse Protocol";
+      }
+      enum "voiceOverAtm" {
+        value 152;
+        description
+          "Voice Over ATM";
+      }
+      enum "voiceOverFrameRelay" {
+        value 153;
+        description
+          "Voice Over Frame Relay";
+      }
+      enum "idsl" {
+        value 154;
+        description
+          "Digital Subscriber Loop over ISDN";
+      }
+      enum "compositeLink" {
+        value 155;
+        description
+          "Avici Composite Link Interface";
+      }
+      enum "ss7SigLink" {
+        value 156;
+        description
+          "SS7 Signaling Link";
+      }
+      enum "propWirelessP2P" {
+        value 157;
+        description
+          "Prop. P2P wireless interface";
+      }
+      enum "frForward" {
+        value 158;
+        description
+          "Frame Forward Interface";
+      }
+      enum "rfc1483" {
+        value 159;
+        description
+          "Multiprotocol over ATM AAL5";
+        reference
+          "RFC 1483 - Multiprotocol Encapsulation over ATM
+                      Adaptation Layer 5";
+      }
+      enum "usb" {
+        value 160;
+        description
+          "USB Interface";
+      }
+      enum "ieee8023adLag" {
+        value 161;
+        description
+          "IEEE 802.3ad Link Aggregate";
+      }
+      enum "bgppolicyaccounting" {
+        value 162;
+        description
+          "BGP Policy Accounting";
+      }
+      enum "frf16MfrBundle" {
+        value 163;
+        description
+          "FRF .16 Multilink Frame Relay";
+      }
+      enum "h323Gatekeeper" {
+        value 164;
+        description
+          "H323 Gatekeeper";
+      }
+      enum "h323Proxy" {
+        value 165;
+        description
+          "H323 Voice and Video Proxy";
+      }
+      enum "mpls" {
+        value 166;
+        description
+          "MPLS";
+      }
+      enum "mfSigLink" {
+        value 167;
+        description
+          "Multi-frequency signaling link";
+      }
+      enum "hdsl2" {
+        value 168;
+        description
+          "High Bit-Rate DSL - 2nd generation";
+      }
+      enum "shdsl" {
+        value 169;
+        description
+          "Multirate HDSL2";
+      }
+      enum "ds1FDL" {
+        value 170;
+        description
+          "Facility Data Link 4Kbps on a DS1";
+      }
+      enum "pos" {
+        value 171;
+        description
+          "Packet over SONET/SDH Interface";
+      }
+      enum "dvbAsiIn" {
+        value 172;
+        description
+          "DVB-ASI Input";
+      }
+      enum "dvbAsiOut" {
+        value 173;
+        description
+          "DVB-ASI Output";
+      }
+      enum "plc" {
+        value 174;
+        description
+          "Power Line Communtications";
+      }
+      enum "nfas" {
+        value 175;
+        description
+          "Non Facility Associated Signaling";
+      }
+      enum "tr008" {
+        value 176;
+        description
+          "TR008";
+      }
+      enum "gr303RDT" {
+        value 177;
+        description
+          "Remote Digital Terminal";
+      }
+      enum "gr303IDT" {
+        value 178;
+        description
+          "Integrated Digital Terminal";
+      }
+      enum "isup" {
+        value 179;
+        description
+          "ISUP";
+      }
+      enum "propDocsWirelessMaclayer" {
+        value 180;
+        description
+          "Cisco proprietary Maclayer";
+      }
+      enum "propDocsWirelessDownstream" {
+        value 181;
+        description
+          "Cisco proprietary Downstream";
+      }
+      enum "propDocsWirelessUpstream" {
+        value 182;
+        description
+          "Cisco proprietary Upstream";
+      }
+      enum "hiperlan2" {
+        value 183;
+        description
+          "HIPERLAN Type 2 Radio Interface";
+      }
+      enum "propBWAp2Mp" {
+        value 184;
+        description
+          "PropBroadbandWirelessAccesspt2multipt use of this value
+           for IEEE 802.16 WMAN interfaces as per IEEE Std 802.16f
+           is deprecated and ieee80216WMAN(237) should be used
+           instead.";
+      }
+      enum "sonetOverheadChannel" {
+        value 185;
+        description
+          "SONET Overhead Channel";
+      }
+      enum "digitalWrapperOverheadChannel" {
+        value 186;
+        description
+          "Digital Wrapper";
+      }
+      enum "aal2" {
+        value 187;
+        description
+          "ATM adaptation layer 2";
+      }
+      enum "radioMAC" {
+        value 188;
+        description
+          "MAC layer over radio links";
+      }
+      enum "atmRadio" {
+        value 189;
+        description
+          "ATM over radio links";
+      }
+      enum "imt" {
+        value 190;
+        description
+          "Inter Machine Trunks";
+      }
+      enum "mvl" {
+        value 191;
+        description
+          "Multiple Virtual Lines DSL";
+      }
+      enum "reachDSL" {
+        value 192;
+        description
+          "Long Reach DSL";
+      }
+      enum "frDlciEndPt" {
+        value 193;
+        description
+          "Frame Relay DLCI End Point";
+      }
+      enum "atmVciEndPt" {
+        value 194;
+        description
+          "ATM VCI End Point";
+      }
+      enum "opticalChannel" {
+        value 195;
+        description
+          "Optical Channel";
+      }
+      enum "opticalTransport" {
+        value 196;
+        description
+          "Optical Transport";
+      }
+      enum "propAtm" {
+        value 197;
+        description
+          "Proprietary ATM";
+      }
+      enum "voiceOverCable" {
+        value 198;
+        description
+          "Voice Over Cable Interface";
+      }
+      enum "infiniband" {
+        value 199;
+        description
+          "Infiniband";
+      }
+      enum "teLink" {
+        value 200;
+        description
+          "TE Link";
+      }
+      enum "q2931" {
+        value 201;
+        description
+          "Q.2931";
+      }
+      enum "virtualTg" {
+        value 202;
+        description
+          "Virtual Trunk Group";
+      }
+      enum "sipTg" {
+        value 203;
+        description
+          "SIP Trunk Group";
+      }
+      enum "sipSig" {
+        value 204;
+        description
+          "SIP Signaling";
+      }
+      enum "docsCableUpstreamChannel" {
+        value 205;
+        description
+          "CATV Upstream Channel";
+      }
+      enum "econet" {
+        value 206;
+        description
+          "Acorn Econet";
+      }
+      enum "pon155" {
+        value 207;
+        description
+          "FSAN 155Mb Symetrical PON interface";
+      }
+      enum "pon622" {
+        value 208;
+        description
+          "FSAN622Mb Symetrical PON interface";
+      }
+      enum "bridge" {
+        value 209;
+        description
+          "Transparent bridge interface";
+      }
+      enum "linegroup" {
+        value 210;
+        description
+          "Interface common to multiple lines";
+      }
+      enum "voiceEMFGD" {
+        value 211;
+        description
+          "voice E&M Feature Group D";
+      }
+      enum "voiceFGDEANA" {
+        value 212;
+        description
+          "voice FGD Exchange Access North American";
+      }
+      enum "voiceDID" {
+        value 213;
+        description
+          "voice Direct Inward Dialing";
+      }
+      enum "mpegTransport" {
+        value 214;
+        description
+          "MPEG transport interface";
+      }
+      enum "sixToFour" {
+        value 215;
+        status deprecated;
+        description
+          "6to4 interface (DEPRECATED)";
+        reference
+          "RFC 4087 - IP Tunnel MIB";
+      }
+      enum "gtp" {
+        value 216;
+        description
+          "GTP (GPRS Tunneling Protocol)";
+      }
+      enum "pdnEtherLoop1" {
+        value 217;
+        description
+          "Paradyne EtherLoop 1";
+      }
+      enum "pdnEtherLoop2" {
+        value 218;
+        description
+          "Paradyne EtherLoop 2";
+      }
+      enum "opticalChannelGroup" {
+        value 219;
+        description
+          "Optical Channel Group";
+      }
+      enum "homepna" {
+        value 220;
+        description
+          "HomePNA ITU-T G.989";
+      }
+      enum "gfp" {
+        value 221;
+        description
+          "Generic Framing Procedure (GFP)";
+      }
+      enum "ciscoISLvlan" {
+        value 222;
+        description
+          "Layer 2 Virtual LAN using Cisco ISL";
+      }
+      enum "actelisMetaLOOP" {
+        value 223;
+        description
+          "Acteleis proprietary MetaLOOP High Speed Link";
+      }
+      enum "fcipLink" {
+        value 224;
+        description
+          "FCIP Link";
+      }
+      enum "rpr" {
+        value 225;
+        description
+          "Resilient Packet Ring Interface Type";
+      }
+      enum "qam" {
+        value 226;
+        description
+          "RF Qam Interface";
+      }
+      enum "lmp" {
+        value 227;
+        description
+          "Link Management Protocol";
+        reference
+          "RFC 4327 - Link Management Protocol (LMP) Management
+                      Information Base (MIB)";
+      }
+      enum "cblVectaStar" {
+        value 228;
+        description
+          "Cambridge Broadband Networks Limited VectaStar";
+      }
+      enum "docsCableMCmtsDownstream" {
+        value 229;
+        description
+          "CATV Modular CMTS Downstream Interface";
+      }
+      enum "adsl2" {
+        value 230;
+        status deprecated;
+        description
+          "Asymmetric Digital Subscriber Loop Version 2
+           (DEPRECATED/OBSOLETED - please use adsl2plus(238)
+           instead)";
+        reference
+          "RFC 4706 - Definitions of Managed Objects for Asymmetric
+                      Digital Subscriber Line 2 (ADSL2)";
+      }
+      enum "macSecControlledIF" {
+        value 231;
+        description
+          "MACSecControlled";
+      }
+      enum "macSecUncontrolledIF" {
+        value 232;
+        description
+          "MACSecUncontrolled";
+      }
+      enum "aviciOpticalEther" {
+        value 233;
+        description
+         "Avici Optical Ethernet Aggregate";
+      }
+      enum "atmbond" {
+        value 234;
+        description
+          "atmbond";
+      }
+      enum "voiceFGDOS" {
+        value 235;
+        description
+          "voice FGD Operator Services";
+      }
+      enum "mocaVersion1" {
+        value 236;
+        description
+          "MultiMedia over Coax Alliance (MoCA) Interface
+           as documented in information provided privately to IANA";
+      }
+      enum "ieee80216WMAN" {
+        value 237;
+        description
+          "IEEE 802.16 WMAN interface";
+      }
+      enum "adsl2plus" {
+        value 238;
+        description
+          "Asymmetric Digital Subscriber Loop Version 2,
+           Version 2 Plus and all variants";
+      }
+      enum "dvbRcsMacLayer" {
+        value 239;
+        description
+          "DVB-RCS MAC Layer";
+        reference
+          "RFC 5728 - The SatLabs Group DVB-RCS MIB";
+      }
+      enum "dvbTdm" {
+        value 240;
+        description
+          "DVB Satellite TDM";
+        reference
+          "RFC 5728 - The SatLabs Group DVB-RCS MIB";
+      }
+      enum "dvbRcsTdma" {
+        value 241;
+        description
+          "DVB-RCS TDMA";
+        reference
+          "RFC 5728 - The SatLabs Group DVB-RCS MIB";
+      }
+      enum "x86Laps" {
+        value 242;
+        description
+          "LAPS based on ITU-T X.86/Y.1323";
+      }
+      enum "wwanPP" {
+        value 243;
+        description
+          "3GPP WWAN";
+      }
+      enum "wwanPP2" {
+        value 244;
+        description
+          "3GPP2 WWAN";
+      }
+      enum "voiceEBS" {
+        value 245;
+        description
+          "voice P-phone EBS physical interface";
+      }
+      enum "ifPwType" {
+        value 246;
+        description
+          "Pseudowire interface type";
+        reference
+          "RFC 5601 - Pseudowire (PW) Management Information Base";
+      }
+      enum "ilan" {
+        value 247;
+        description
+          "Internal LAN on a bridge per IEEE 802.1ap";
+      }
+      enum "pip" {
+        value 248;
+        description
+          "Provider Instance Port on a bridge per IEEE 802.1ah PBB";
+      }
+      enum "aluELP" {
+        value 249;
+        description
+          "Alcatel-Lucent Ethernet Link Protection";
+      }
+      enum "gpon" {
+        value 250;
+        description
+          "Gigabit-capable passive optical networks (G-PON) as per
+           ITU-T G.948";
+      }
+      enum "vdsl2" {
+        value 251;
+        description
+          "Very high speed digital subscriber line Version 2
+           (as per ITU-T Recommendation G.993.2)";
+        reference
+          "RFC 5650 - Definitions of Managed Objects for Very High
+                      Speed Digital Subscriber Line 2 (VDSL2)";
+      }
+      enum "capwapDot11Profile" {
+        value 252;
+        description
+          "WLAN Profile Interface";
+        reference
+          "RFC 5834 - Control and Provisioning of Wireless Access
+                      Points (CAPWAP) Protocol Binding MIB for
+                      IEEE 802.11";
+      }
+      enum "capwapDot11Bss" {
+        value 253;
+        description
+          "WLAN BSS Interface";
+        reference
+          "RFC 5834 - Control and Provisioning of Wireless Access
+                      Points (CAPWAP) Protocol Binding MIB for
+                      IEEE 802.11";
+      }
+      enum "capwapWtpVirtualRadio" {
+        value 254;
+        description
+          "WTP Virtual Radio Interface";
+        reference
+          "RFC 5833 - Control and Provisioning of Wireless Access
+                      Points (CAPWAP) Protocol Base MIB";
+      }
+      enum "bits" {
+        value 255;
+        description
+          "bitsport";
+      }
+      enum "docsCableUpstreamRfPort" {
+        value 256;
+        description
+          "DOCSIS CATV Upstream RF Port";
+      }
+      enum "cableDownstreamRfPort" {
+        value 257;
+        description
+          "CATV downstream RF port";
+      }
+      enum "vmwareVirtualNic" {
+        value 258;
+        description
+          "VMware Virtual Network Interface";
+      }
+      enum "ieee802154" {
+        value 259;
+        description
+          "IEEE 802.15.4 WPAN interface";
+        reference
+          "IEEE 802.15.4-2006";
+      }
+      enum "otnOdu" {
+        value 260;
+        description
+          "OTN Optical Data Unit";
+      }
+      enum "otnOtu" {
+        value 261;
+        description
+          "OTN Optical channel Transport Unit";
+      }
+      enum "ifVfiType" {
+        value 262;
+        description
+          "VPLS Forwarding Instance Interface Type";
+      }
+      enum "g9981" {
+        value 263;
+        description
+          "G.998.1 bonded interface";
+      }
+      enum "g9982" {
+        value 264;
+        description
+          "G.998.2 bonded interface";
+      }
+      enum "g9983" {
+        value 265;
+        description
+          "G.998.3 bonded interface";
+      }
+      enum "aluEpon" {
+        value 266;
+        description
+          "Ethernet Passive Optical Networks (E-PON)";
+      }
+      enum "aluEponOnu" {
+        value 267;
+        description
+          "EPON Optical Network Unit";
+      }
+      enum "aluEponPhysicalUni" {
+        value 268;
+        description
+          "EPON physical User to Network interface";
+      }
+      enum "aluEponLogicalLink" {
+        value 269;
+        description
+          "The emulation of a point-to-point link over the EPON
+           layer";
+      }
+      enum "aluGponOnu" {
+        value 270;
+        description
+          "GPON Optical Network Unit";
+        reference
+          "ITU-T G.984.2";
+      }
+      enum "aluGponPhysicalUni" {
+        value 271;
+        description
+          "GPON physical User to Network interface";
+        reference
+          "ITU-T G.984.2";
+      }
+      enum "vmwareNicTeam" {
+        value 272;
+        description
+          "VMware NIC Team";
+      }
+      // value 273 reserved by IANA
+    }
+    description
+      "This data type is used as the syntax of the 'type'
+       leaf in the 'interface' list in the YANG module
+       ietf-interface.
+
+       The definition of this typedef with the
+       addition of newly assigned values is published
+       periodically by the IANA, in either the Assigned
+       Numbers RFC, or some derivative of it specific to
+       Internet Network Management number assignments.  (The
+       latest arrangements can be obtained by contacting the
+       IANA.)
+
+       Requests for new values should be made to IANA via
+       email (iana&iana.org).";
+    reference
+      "IANA ifType definitions registry.
+       <http://www.iana.org/assignments/smi-numbers>";
+  }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/ietf-inet-types.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/ietf-inet-types.yang
new file mode 100644 (file)
index 0000000..de20feb
--- /dev/null
@@ -0,0 +1,418 @@
+ module ietf-inet-types {
+
+   namespace "urn:ietf:params:xml:ns:yang:ietf-inet-types";
+   prefix "inet";
+
+   organization
+    "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+   contact
+    "WG Web:   <http://tools.ietf.org/wg/netmod/>
+     WG List:  <mailto:netmod@ietf.org>
+
+     WG Chair: David Partain
+               <mailto:david.partain@ericsson.com>
+
+     WG Chair: David Kessens
+               <mailto:david.kessens@nsn.com>
+
+     Editor:   Juergen Schoenwaelder
+               <mailto:j.schoenwaelder@jacobs-university.de>";
+
+   description
+    "This module contains a collection of generally useful derived
+     YANG data types for Internet addresses and related things.
+
+     Copyright (c) 2010 IETF Trust and the persons identified as
+     authors of the code.  All rights reserved.
+
+     Redistribution and use in source and binary forms, with or without
+     modification, is permitted pursuant to, and subject to the license
+     terms contained in, the Simplified BSD License set forth in Section
+     4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
+     (http://trustee.ietf.org/license-info).
+
+     This version of this YANG module is part of RFC 6021; see
+     the RFC itself for full legal notices.";
+
+   revision 2010-09-24 {
+     description
+      "Initial revision.";
+     reference
+      "RFC 6021: Common YANG Data Types";
+   }
+
+   /*** collection of protocol field related types ***/
+
+   typedef ip-version {
+     type enumeration {
+       enum unknown {
+         value "0";
+         description
+          "An unknown or unspecified version of the Internet protocol.";
+       }
+       enum ipv4 {
+         value "1";
+         description
+          "The IPv4 protocol as defined in RFC 791.";
+       }
+       enum ipv6 {
+         value "2";
+         description
+          "The IPv6 protocol as defined in RFC 2460.";
+       }
+     }
+     description
+      "This value represents the version of the IP protocol.
+
+       In the value set and its semantics, this type is equivalent
+       to the InetVersion textual convention of the SMIv2.";
+     reference
+      "RFC  791: Internet Protocol
+       RFC 2460: Internet Protocol, Version 6 (IPv6) Specification
+       RFC 4001: Textual Conventions for Internet Network Addresses";
+   }
+
+   typedef dscp {
+     type uint8 {
+       range "0..63";
+     }
+     description
+      "The dscp type represents a Differentiated Services Code-Point
+       that may be used for marking packets in a traffic stream.
+
+       In the value set and its semantics, this type is equivalent
+       to the Dscp textual convention of the SMIv2.";
+     reference
+      "RFC 3289: Management Information Base for the Differentiated
+                 Services Architecture
+       RFC 2474: Definition of the Differentiated Services Field
+                 (DS Field) in the IPv4 and IPv6 Headers
+       RFC 2780: IANA Allocation Guidelines For Values In
+                 the Internet Protocol and Related Headers";
+   }
+
+   typedef ipv6-flow-label {
+     type uint32 {
+       range "0..1048575";
+     }
+     description
+      "The flow-label type represents flow identifier or Flow Label
+       in an IPv6 packet header that may be used to discriminate
+       traffic flows.
+
+       In the value set and its semantics, this type is equivalent
+       to the IPv6FlowLabel textual convention of the SMIv2.";
+     reference
+      "RFC 3595: Textual Conventions for IPv6 Flow Label
+       RFC 2460: Internet Protocol, Version 6 (IPv6) Specification";
+   }
+
+   typedef port-number {
+     type uint16 {
+       range "0..65535";
+     }
+     description
+      "The port-number type represents a 16-bit port number of an
+       Internet transport layer protocol such as UDP, TCP, DCCP, or
+       SCTP.  Port numbers are assigned by IANA.  A current list of
+       all assignments is available from <http://www.iana.org/>.
+
+       Note that the port number value zero is reserved by IANA.  In
+       situations where the value zero does not make sense, it can
+       be excluded by subtyping the port-number type.
+
+       In the value set and its semantics, this type is equivalent
+       to the InetPortNumber textual convention of the SMIv2.";
+     reference
+      "RFC  768: User Datagram Protocol
+       RFC  793: Transmission Control Protocol
+       RFC 4960: Stream Control Transmission Protocol
+       RFC 4340: Datagram Congestion Control Protocol (DCCP)
+       RFC 4001: Textual Conventions for Internet Network Addresses";
+   }
+
+   /*** collection of autonomous system related types ***/
+
+   typedef as-number {
+     type uint32;
+     description
+      "The as-number type represents autonomous system numbers
+       which identify an Autonomous System (AS).  An AS is a set
+       of routers under a single technical administration, using
+       an interior gateway protocol and common metrics to route
+       packets within the AS, and using an exterior gateway
+       protocol to route packets to other ASs'.  IANA maintains
+       the AS number space and has delegated large parts to the
+       regional registries.
+
+       Autonomous system numbers were originally limited to 16
+       bits.  BGP extensions have enlarged the autonomous system
+       number space to 32 bits.  This type therefore uses an uint32
+       base type without a range restriction in order to support
+       a larger autonomous system number space.
+
+       In the value set and its semantics, this type is equivalent
+       to the InetAutonomousSystemNumber textual convention of
+       the SMIv2.";
+     reference
+      "RFC 1930: Guidelines for creation, selection, and registration
+                 of an Autonomous System (AS)
+       RFC 4271: A Border Gateway Protocol 4 (BGP-4)
+       RFC 4893: BGP Support for Four-octet AS Number Space
+       RFC 4001: Textual Conventions for Internet Network Addresses";
+   }
+
+   /*** collection of IP address and hostname related types ***/
+
+   typedef ip-address {
+     type union {
+       type inet:ipv4-address;
+       type inet:ipv6-address;
+     }
+     description
+      "The ip-address type represents an IP address and is IP
+       version neutral.  The format of the textual representations
+       implies the IP version.";
+   }
+
+   typedef ipv4-address {
+     type string {
+       pattern
+         '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+       +  '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+       + '(%[\p{N}\p{L}]+)?';
+     }
+     description
+       "The ipv4-address type represents an IPv4 address in
+        dotted-quad notation.  The IPv4 address may include a zone
+        index, separated by a % sign.
+
+        The zone index is used to disambiguate identical address
+        values.  For link-local addresses, the zone index will
+        typically be the interface index number or the name of an
+        interface.  If the zone index is not present, the default
+        zone of the device will be used.
+
+        The canonical format for the zone index is the numerical
+        format";
+   }
+
+   typedef ipv6-address {
+     type string {
+       pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+             + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+             + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+             + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+             + '(%[\p{N}\p{L}]+)?';
+       pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+             + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+             + '(%.+)?';
+     }
+     description
+      "The ipv6-address type represents an IPv6 address in full,
+       mixed, shortened, and shortened-mixed notation.  The IPv6
+       address may include a zone index, separated by a % sign.
+
+       The zone index is used to disambiguate identical address
+       values.  For link-local addresses, the zone index will
+       typically be the interface index number or the name of an
+       interface.  If the zone index is not present, the default
+       zone of the device will be used.
+
+       The canonical format of IPv6 addresses uses the compressed
+       format described in RFC 4291, Section 2.2, item 2 with the
+       following additional rules: the :: substitution must be
+       applied to the longest sequence of all-zero 16-bit chunks
+       in an IPv6 address.  If there is a tie, the first sequence
+       of all-zero 16-bit chunks is replaced by ::.  Single
+       all-zero 16-bit chunks are not compressed.  The canonical
+       format uses lowercase characters and leading zeros are
+       not allowed.  The canonical format for the zone index is
+       the numerical format as described in RFC 4007, Section
+       11.2.";
+     reference
+      "RFC 4291: IP Version 6 Addressing Architecture
+       RFC 4007: IPv6 Scoped Address Architecture
+       RFC 5952: A Recommendation for IPv6 Address Text Representation";
+   }
+
+   typedef ip-prefix {
+     type union {
+       type inet:ipv4-prefix;
+       type inet:ipv6-prefix;
+     }
+     description
+      "The ip-prefix type represents an IP prefix and is IP
+       version neutral.  The format of the textual representations
+       implies the IP version.";
+   }
+
+   typedef ipv4-prefix {
+     type string {
+       pattern
+          '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+        +  '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+        + '/(([0-9])|([1-2][0-9])|(3[0-2]))';
+     }
+     description
+      "The ipv4-prefix type represents an IPv4 address prefix.
+       The prefix length is given by the number following the
+       slash character and must be less than or equal to 32.
+
+       A prefix length value of n corresponds to an IP address
+       mask that has n contiguous 1-bits from the most
+       significant bit (MSB) and all other bits set to 0.
+
+       The canonical format of an IPv4 prefix has all bits of
+       the IPv4 address set to zero that are not part of the
+       IPv4 prefix.";
+   }
+
+   typedef ipv6-prefix {
+     type string {
+       pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+             + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+             + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+             + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+             + '(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8])))';
+       pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+             + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+             + '(/.+)';
+     }
+     description
+      "The ipv6-prefix type represents an IPv6 address prefix.
+       The prefix length is given by the number following the
+       slash character and must be less than or equal 128.
+
+       A prefix length value of n corresponds to an IP address
+       mask that has n contiguous 1-bits from the most
+       significant bit (MSB) and all other bits set to 0.
+
+       The IPv6 address should have all bits that do not belong
+       to the prefix set to zero.
+
+       The canonical format of an IPv6 prefix has all bits of
+       the IPv6 address set to zero that are not part of the
+       IPv6 prefix.  Furthermore, IPv6 address is represented
+       in the compressed format described in RFC 4291, Section
+       2.2, item 2 with the following additional rules: the ::
+       substitution must be applied to the longest sequence of
+       all-zero 16-bit chunks in an IPv6 address.  If there is
+       a tie, the first sequence of all-zero 16-bit chunks is
+       replaced by ::.  Single all-zero 16-bit chunks are not
+       compressed.  The canonical format uses lowercase
+       characters and leading zeros are not allowed.";
+     reference
+      "RFC 4291: IP Version 6 Addressing Architecture";
+   }
+
+   /*** collection of domain name and URI types ***/
+
+   typedef domain-name {
+     type string {
+       pattern '((([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.)*'
+            +  '([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.?)'
+            +  '|\.';
+       length "1..253";
+     }
+     description
+      "The domain-name type represents a DNS domain name.  The
+       name SHOULD be fully qualified whenever possible.
+
+       Internet domain names are only loosely specified.  Section
+       3.5 of RFC 1034 recommends a syntax (modified in Section
+       2.1 of RFC 1123).  The pattern above is intended to allow
+       for current practice in domain name use, and some possible
+       future expansion.  It is designed to hold various types of
+       domain names, including names used for A or AAAA records
+       (host names) and other records, such as SRV records.  Note
+       that Internet host names have a stricter syntax (described
+       in RFC 952) than the DNS recommendations in RFCs 1034 and
+       1123, and that systems that want to store host names in
+       schema nodes using the domain-name type are recommended to
+       adhere to this stricter standard to ensure interoperability.
+
+       The encoding of DNS names in the DNS protocol is limited
+       to 255 characters.  Since the encoding consists of labels
+       prefixed by a length bytes and there is a trailing NULL
+       byte, only 253 characters can appear in the textual dotted
+       notation.
+
+       The description clause of schema nodes using the domain-name
+       type MUST describe when and how these names are resolved to
+       IP addresses.  Note that the resolution of a domain-name value
+       may require to query multiple DNS records (e.g., A for IPv4
+       and AAAA for IPv6).  The order of the resolution process and
+       which DNS record takes precedence can either be defined
+       explicitely or it may depend on the configuration of the
+       resolver.
+
+       Domain-name values use the US-ASCII encoding.  Their canonical
+       format uses lowercase US-ASCII characters.  Internationalized
+       domain names MUST be encoded in punycode as described in RFC
+       3492";
+     reference
+      "RFC  952: DoD Internet Host Table Specification
+       RFC 1034: Domain Names - Concepts and Facilities
+       RFC 1123: Requirements for Internet Hosts -- Application
+                 and Support
+       RFC 2782: A DNS RR for specifying the location of services
+                 (DNS SRV)
+       RFC 3492: Punycode: A Bootstring encoding of Unicode for
+                 Internationalized Domain Names in Applications
+                 (IDNA)
+       RFC 5891: Internationalizing Domain Names in Applications
+                 (IDNA): Protocol";
+   }
+
+   typedef host {
+     type union {
+       type inet:ip-address;
+       type inet:domain-name;
+     }
+     description
+      "The host type represents either an IP address or a DNS
+       domain name.";
+   }
+
+   typedef uri {
+     type string;
+     description
+      "The uri type represents a Uniform Resource Identifier
+       (URI) as defined by STD 66.
+
+       Objects using the uri type MUST be in US-ASCII encoding,
+       and MUST be normalized as described by RFC 3986 Sections
+       6.2.1, 6.2.2.1, and 6.2.2.2.  All unnecessary
+       percent-encoding is removed, and all case-insensitive
+       characters are set to lowercase except for hexadecimal
+       digits, which are normalized to uppercase as described in
+       Section 6.2.2.1.
+
+       The purpose of this normalization is to help provide
+       unique URIs.  Note that this normalization is not
+       sufficient to provide uniqueness.  Two URIs that are
+       textually distinct after this normalization may still be
+       equivalent.
+
+       Objects using the uri type may restrict the schemes that
+       they permit.  For example, 'data:' and 'urn:' schemes
+       might not be appropriate.
+
+       A zero-length URI is not a valid URI.  This can be used to
+       express 'URI absent' where required.
+
+       In the value set and its semantics, this type is equivalent
+       to the Uri SMIv2 textual convention defined in RFC 5017.";
+     reference
+      "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax
+       RFC 3305: Report from the Joint W3C/IETF URI Planning Interest
+                 Group: Uniform Resource Identifiers (URIs), URLs,
+                 and Uniform Resource Names (URNs): Clarifications
+                 and Recommendations
+       RFC 5017: MIB Textual Conventions for Uniform Resource
+                 Identifiers (URIs)";
+   }
+
+ }
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/ietf-interfaces@2013-07-04.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/ietf-interfaces@2013-07-04.yang
new file mode 100644 (file)
index 0000000..9db753c
--- /dev/null
@@ -0,0 +1,673 @@
+module ietf-interfaces {
+
+  namespace "urn:ietf:params:xml:ns:yang:ietf-interfaces";
+  prefix if;
+
+  import ietf-yang-types {
+    prefix yang;
+  }
+  import iana-if-type {
+    prefix ianaift;
+  }
+
+  organization
+    "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+  contact
+    "WG Web:   <http://tools.ietf.org/wg/netmod/>
+     WG List:  <mailto:netmod@ietf.org>
+
+     WG Chair: David Kessens
+               <mailto:david.kessens@nsn.com>
+
+     WG Chair: Juergen Schoenwaelder
+               <mailto:j.schoenwaelder@jacobs-university.de>
+
+     Editor:   Martin Bjorklund
+               <mailto:mbj@tail-f.com>";
+
+  description
+    "This module contains a collection of YANG definitions for
+     managing network interfaces.
+
+     Copyright (c) 2013 IETF Trust and the persons identified as
+     authors of the code.  All rights reserved.
+
+     Redistribution and use in source and binary forms, with or
+     without modification, is permitted pursuant to, and subject
+     to the license terms contained in, the Simplified BSD License
+     set forth in Section 4.c of the IETF Trust's Legal Provisions
+     Relating to IETF Documents
+     (http://trustee.ietf.org/license-info).
+
+     This version of this YANG module is part of RFC XXXX; see
+     the RFC itself for full legal notices.";
+
+  // RFC Ed.: replace XXXX with actual RFC number and remove this
+  // note.
+
+  // RFC Ed.: update the date below with the date of RFC publication
+  // and remove this note.
+  revision 2013-07-04 {
+    description
+      "Initial revision.";
+    reference
+      "RFC XXXX: A YANG Data Model for Interface Management";
+  }
+
+  /* Typedefs */
+
+  typedef interface-ref {
+    type leafref {
+      path "/if:interfaces/if:interface/if:name";
+    }
+    description
+      "This type is used by data models that need to reference
+       configured interfaces.";
+  }
+
+  typedef interface-state-ref {
+    type leafref {
+      path "/if:interfaces-state/if:interface/if:name";
+    }
+    description
+      "This type is used by data models that need to reference
+       the operationally present interfaces.";
+  }
+
+  /* Features */
+
+  feature arbitrary-names {
+    description
+      "This feature indicates that the device allows user-controlled
+       interfaces to be named arbitrarily.";
+  }
+
+  feature pre-provisioning {
+    description
+      "This feature indicates that the device supports
+       pre-provisioning of interface configuration, i.e., it is
+       possible to configure an interface whose physical interface
+       hardware is not present on the device.";
+  }
+
+  feature if-mib {
+    description
+      "This feature indicates that the device implements IF-MIB.";
+    reference
+      "RFC 2863: The Interfaces Group MIB";
+  }
+
+  /* Data nodes */
+
+  container interfaces {
+    description
+      "Interface configuration parameters.";
+
+    list interface {
+      key "name";
+
+      description
+        "The list of configured interfaces on the device.
+
+         The operational state of an interface is available in the
+         /interfaces-state/interface list.  If the configuration of a
+         system-controlled interface cannot be used by the system
+         (e.g., the interface hardware present does not match the
+         interface type), then the configuration is not applied to
+         the system-controlled interface shown in the
+         /interfaces-state/interface list.  If the the configuration
+         of a user-controlled interface cannot be used by the system,
+         the configured interface is not instantiated in the
+         /interfaces-state/interface list.";
+
+     leaf name {
+        type string;
+        description
+          "The name of the interface.
+
+           A device MAY restrict the allowed values for this leaf,
+           possibly depending on the type of the interface.
+
+           For system-controlled interfaces, this leaf is the
+           device-specific name of the interface.  The 'config false'
+           list /interfaces-state/interface contains the currently
+           existing interfaces on the device.
+
+           If a client tries to create configuration for a
+           system-controlled interface that is not present in the
+           /interfaces-state/interface list, the server MAY reject
+           the request, if the implementation does not support
+           pre-provisioning of interfaces, or if the name refers to
+           an interface that can never exist in the system.  A
+           NETCONF server MUST reply with an rpc-error with the
+           error-tag 'invalid-value' in this case.
+
+           If the device supports pre-provisioning of interface
+           configuration, the feature 'pre-provisioning' is
+           advertised.
+
+           If the device allows arbitrarily named user-controlled
+           interfaces, the feature 'arbitrary-names' is advertised.
+
+           When a configured user-controlled interface is created by
+           the system, it is instantiated with the same name in the
+           /interface-state/interface list.  Since the name in that
+           list MAY be mapped to ifName by an implementation, such an
+           implementation MUST restrict the allowed values for this
+           leaf so that it matches the restrictions of ifName.
+
+           If a NETCONF server that implements this restriction is
+           sent a value that doesn't match the restriction, it MUST
+           reply with an rpc-error with the error-tag
+           'invalid-value'.";
+      }
+
+      leaf description {
+        type string;
+        description
+          "A textual description of the interface.
+
+           This leaf MAY be mapped to ifAlias by an implementation.
+           Such an implementation MUST restrict the allowed values
+           for this leaf so that it matches the restrictions of
+           ifAlias.
+
+           If a NETCONF server that implements this restriction is
+           sent a value that doesn't match the restriction, it MUST
+           reply with an rpc-error with the error-tag
+           'invalid-value'.
+
+           Since ifAlias is defined to be stored in non-volatile
+           storage, the MIB implementation MUST map ifAlias to the
+           value of 'description' in the persistently stored
+           datastore.
+
+           Specifically, if the device supports ':startup', when
+           ifAlias is read the device MUST return the value of
+           'description' in the 'startup' datastore, and when it is
+           written, it MUST be written to the 'running' and 'startup'
+           datastores.  Note that it is up to the implementation if
+           it modifies this single leaf in 'startup', or if it
+           performs an implicit copy-config from 'running' to
+           'startup'.
+
+           If the device does not support ':startup', ifAlias MUST
+           be mapped to the 'description' leaf in the 'running'
+           datastore.";
+        reference
+          "RFC 2863: The Interfaces Group MIB - ifAlias";
+      }
+
+      leaf type {
+        type ianaift:iana-if-type;
+        mandatory true;
+        description
+          "The type of the interface.
+
+           When an interface entry is created, a server MAY
+           initialize the type leaf with a valid value, e.g., if it
+           is possible to derive the type from the name of the
+           interface.
+
+           If a client tries to set the type of an interface to a
+           value that can never be used by the system, e.g., if the
+           type is not supported or if the type does not match the
+           name of the interface, the server MUST reject the request.
+           A NETCONF server MUST reply with an rpc-error with the
+           error-tag 'invalid-value' in this case.";
+        reference
+          "RFC 2863: The Interfaces Group MIB - ifType";
+      }
+
+      leaf enabled {
+        type boolean;
+        default "true";
+        description
+          "This leaf contains the configured, desired state of the
+           interface.
+
+           Systems that implement the IF-MIB use the value of this
+           leaf in the 'running' datastore to set
+           IF-MIB.ifAdminStatus to 'up' or 'down' after an ifEntry
+           has been initialized, as described in RFC 2863.
+
+           Changes in this leaf in the 'running' datastore are
+           reflected in ifAdminStatus, but if ifAdminStatus is
+           changed over SNMP, this leaf is not affected.";
+        reference
+          "RFC 2863: The Interfaces Group MIB - ifAdminStatus";
+      }
+
+      leaf link-up-down-trap-enable {
+        if-feature if-mib;
+        type enumeration {
+          enum enabled {
+            value 1;
+          }
+          enum disabled {
+            value 2;
+          }
+        }
+        description
+          "Controls whether linkUp/linkDown SNMP notifications
+           should be generated for this interface.
+
+           If this node is not configured, the value 'enabled' is
+           operationally used by the server for interfaces which do
+           not operate on top of any other interface (i.e., there are
+           no 'lower-layer-if' entries), and 'disabled' otherwise.";
+        reference
+          "RFC 2863: The Interfaces Group MIB -
+                     ifLinkUpDownTrapEnable";
+      }
+    }
+  }
+
+  container interfaces-state {
+    config false;
+    description
+      "Data nodes for the operational state of interfaces.";
+
+    list interface {
+      key "name";
+
+      description
+        "The list of interfaces on the device.
+
+         System-controlled interfaces created by the system are
+         always present in this list, whether they are configured or
+         not.";
+
+      leaf name {
+        type string;
+        description
+          "The name of the interface.
+
+           This leaf MAY be mapped to ifName by an implementation.";
+        reference
+          "RFC 2863: The Interfaces Group MIB - ifName";
+      }
+
+      leaf type {
+        type ianaift:iana-if-type;
+        mandatory true;
+        description
+          "The type of the interface.";
+        reference
+          "RFC 2863: The Interfaces Group MIB - ifType";
+      }
+
+      leaf admin-status {
+        if-feature if-mib;
+        type enumeration {
+          enum up {
+            value 1;
+            description
+              "Ready to pass packets.";
+          }
+          enum down {
+            value 2;
+            description
+              "Not ready to pass packets and not in some test mode.";
+          }
+          enum testing {
+            value 3;
+            description
+              "In some test mode.";
+          }
+        }
+        mandatory true;
+        description
+          "The desired state of the interface.
+
+           This leaf has the same read semantics as ifAdminStatus.";
+        reference
+          "RFC 2863: The Interfaces Group MIB - ifAdminStatus";
+      }
+
+      leaf oper-status {
+        type enumeration {
+          enum up {
+            value 1;
+            description
+              "Ready to pass packets.";
+          }
+          enum down {
+            value 2;
+            description
+              "The interface does not pass any packets.";
+          }
+          enum testing {
+            value 3;
+            description
+              "In some test mode.  No operational packets can
+               be passed.";
+          }
+          enum unknown {
+            value 4;
+            description
+              "Status cannot be determined for some reason.";
+          }
+          enum dormant {
+            value 5;
+            description
+              "Waiting for some external event.";
+          }
+          enum not-present {
+            value 6;
+            description
+              "Some component (typically hardware) is missing.";
+          }
+          enum lower-layer-down {
+            value 7;
+            description
+              "Down due to state of lower-layer interface(s).";
+          }
+        }
+        mandatory true;
+        description
+          "The current operational state of the interface.
+
+           This leaf has the same semantics as ifOperStatus.";
+        reference
+          "RFC 2863: The Interfaces Group MIB - ifOperStatus";
+      }
+
+      leaf last-change {
+        type yang:date-and-time;
+        description
+          "The time the interface entered its current operational
+           state.  If the current state was entered prior to the
+           last re-initialization of the local network management
+           subsystem, then this node is not present.";
+        reference
+          "RFC 2863: The Interfaces Group MIB - ifLastChange";
+      }
+
+      leaf if-index {
+        if-feature if-mib;
+        type int32 {
+          range "1..2147483647";
+        }
+        mandatory true;
+        description
+          "The ifIndex value for the ifEntry represented by this
+           interface.";
+        reference
+          "RFC 2863: The Interfaces Group MIB - ifIndex";
+      }
+
+      leaf phys-address {
+        type yang:phys-address;
+        description
+          "The interface's address at its protocol sub-layer.  For
+          example, for an 802.x interface, this object normally
+          contains a MAC address.  The interface's media-specific
+          modules must define the bit and byte ordering and the
+          format of the value of this object.  For interfaces that do
+          not have such an address (e.g., a serial line), this node
+          is not present.";
+        reference
+          "RFC 2863: The Interfaces Group MIB - ifPhysAddress";
+      }
+
+      leaf-list higher-layer-if {
+        type interface-state-ref;
+        description
+          "A list of references to interfaces layered on top of this
+           interface.";
+        reference
+          "RFC 2863: The Interfaces Group MIB - ifStackTable";
+      }
+
+      leaf-list lower-layer-if {
+        type interface-state-ref;
+        description
+          "A list of references to interfaces layered underneath this
+           interface.";
+        reference
+          "RFC 2863: The Interfaces Group MIB - ifStackTable";
+      }
+
+      leaf speed {
+        type yang:gauge64;
+        units "bits / second";
+        description
+            "An estimate of the interface's current bandwidth in bits
+             per second.  For interfaces that do not vary in
+             bandwidth or for those where no accurate estimation can
+             be made, this node should contain the nominal bandwidth.
+             For interfaces that have no concept of bandwidth, this
+             node is not present.";
+        reference
+          "RFC 2863: The Interfaces Group MIB -
+                     ifSpeed, ifHighSpeed";
+      }
+
+      container statistics {
+        description
+          "A collection of interface-related statistics objects.";
+
+        leaf discontinuity-time {
+          type yang:date-and-time;
+          mandatory true;
+          description
+            "The time on the most recent occasion at which any one or
+             more of this interface's counters suffered a
+             discontinuity.  If no such discontinuities have occurred
+             since the last re-initialization of the local management
+             subsystem, then this node contains the time the local
+             management subsystem re-initialized itself.";
+        }
+
+        leaf in-octets {
+          type yang:counter64;
+          description
+            "The total number of octets received on the interface,
+             including framing characters.
+
+             Discontinuities in the value of this counter can occur
+             at re-initialization of the management system, and at
+             other times as indicated by the value of
+             'discontinuity-time'.";
+          reference
+            "RFC 2863: The Interfaces Group MIB - ifHCInOctets";
+        }
+        leaf in-unicast-pkts {
+          type yang:counter64;
+          description
+            "The number of packets, delivered by this sub-layer to a
+             higher (sub-)layer, which were not addressed to a
+             multicast or broadcast address at this sub-layer.
+
+             Discontinuities in the value of this counter can occur
+             at re-initialization of the management system, and at
+             other times as indicated by the value of
+             'discontinuity-time'.";
+          reference
+            "RFC 2863: The Interfaces Group MIB - ifHCInUcastPkts";
+        }
+        leaf in-broadcast-pkts {
+          type yang:counter64;
+          description
+            "The number of packets, delivered by this sub-layer to a
+             higher (sub-)layer, which were addressed to a broadcast
+             address at this sub-layer.
+
+             Discontinuities in the value of this counter can occur
+             at re-initialization of the management system, and at
+             other times as indicated by the value of
+             'discontinuity-time'.";
+          reference
+            "RFC 2863: The Interfaces Group MIB -
+                       ifHCInBroadcastPkts";
+        }
+        leaf in-multicast-pkts {
+          type yang:counter64;
+          description
+            "The number of packets, delivered by this sub-layer to a
+             higher (sub-)layer, which were addressed to a multicast
+             address at this sub-layer.  For a MAC layer protocol,
+             this includes both Group and Functional addresses.
+
+             Discontinuities in the value of this counter can occur
+             at re-initialization of the management system, and at
+             other times as indicated by the value of
+             'discontinuity-time'.";
+          reference
+            "RFC 2863: The Interfaces Group MIB -
+                       ifHCInMulticastPkts";
+        }
+        leaf in-discards {
+          type yang:counter32;
+          description
+            "The number of inbound packets which were chosen to be
+             discarded even though no errors had been detected to
+             prevent their being deliverable to a higher-layer
+             protocol.  One possible reason for discarding such a
+             packet could be to free up buffer space.
+
+             Discontinuities in the value of this counter can occur
+             at re-initialization of the management system, and at
+             other times as indicated by the value of
+             'discontinuity-time'.";
+          reference
+            "RFC 2863: The Interfaces Group MIB - ifInDiscards";
+        }
+        leaf in-errors {
+          type yang:counter32;
+          description
+            "For packet-oriented interfaces, the number of inbound
+             packets that contained errors preventing them from being
+             deliverable to a higher-layer protocol.  For character-
+             oriented or fixed-length interfaces, the number of
+             inbound transmission units that contained errors
+             preventing them from being deliverable to a higher-layer
+             protocol.
+
+             Discontinuities in the value of this counter can occur
+             at re-initialization of the management system, and at
+             other times as indicated by the value of
+             'discontinuity-time'.";
+          reference
+            "RFC 2863: The Interfaces Group MIB - ifInErrors";
+        }
+        leaf in-unknown-protos {
+          type yang:counter32;
+          description
+            "For packet-oriented interfaces, the number of packets
+             received via the interface which were discarded because
+             of an unknown or unsupported protocol.  For
+             character-oriented or fixed-length interfaces that
+             support protocol multiplexing the number of transmission
+             units received via the interface which were discarded
+             because of an unknown or unsupported protocol.  For any
+             interface that does not support protocol multiplexing,
+             this counter is not present.
+             Discontinuities in the value of this counter can occur
+             at re-initialization of the management system, and at
+             other times as indicated by the value of
+             'discontinuity-time'.";
+          reference
+            "RFC 2863: The Interfaces Group MIB - ifInUnknownProtos";
+        }
+
+        leaf out-octets {
+          type yang:counter64;
+          description
+            "The total number of octets transmitted out of the
+             interface, including framing characters.
+
+             Discontinuities in the value of this counter can occur
+             at re-initialization of the management system, and at
+             other times as indicated by the value of
+             'discontinuity-time'.";
+          reference
+            "RFC 2863: The Interfaces Group MIB - ifHCOutOctets";
+        }
+        leaf out-unicast-pkts {
+          type yang:counter64;
+          description
+            "The total number of packets that higher-level protocols
+             requested be transmitted, and which were not addressed
+             to a multicast or broadcast address at this sub-layer,
+             including those that were discarded or not sent.
+
+             Discontinuities in the value of this counter can occur
+             at re-initialization of the management system, and at
+             other times as indicated by the value of
+             'discontinuity-time'.";
+          reference
+            "RFC 2863: The Interfaces Group MIB - ifHCOutUcastPkts";
+        }
+        leaf out-broadcast-pkts {
+          type yang:counter64;
+          description
+            "The total number of packets that higher-level protocols
+             requested be transmitted, and which were addressed to a
+             broadcast address at this sub-layer, including those
+             that were discarded or not sent.
+
+             Discontinuities in the value of this counter can occur
+             at re-initialization of the management system, and at
+             other times as indicated by the value of
+             'discontinuity-time'.";
+          reference
+            "RFC 2863: The Interfaces Group MIB -
+                       ifHCOutBroadcastPkts";
+        }
+        leaf out-multicast-pkts {
+          type yang:counter64;
+          description
+            "The total number of packets that higher-level protocols
+             requested be transmitted, and which were addressed to a
+             multicast address at this sub-layer, including those
+             that were discarded or not sent.  For a MAC layer
+             protocol, this includes both Group and Functional
+             addresses.
+
+             Discontinuities in the value of this counter can occur
+             at re-initialization of the management system, and at
+             other times as indicated by the value of
+             'discontinuity-time'.";
+          reference
+            "RFC 2863: The Interfaces Group MIB -
+                       ifHCOutMulticastPkts";
+        }
+        leaf out-discards {
+          type yang:counter32;
+          description
+            "The number of outbound packets which were chosen to be
+             discarded even though no errors had been detected to
+             prevent their being transmitted.  One possible reason
+             for discarding such a packet could be to free up buffer
+             space.
+
+             Discontinuities in the value of this counter can occur
+             at re-initialization of the management system, and at
+             other times as indicated by the value of
+             'discontinuity-time'.";
+          reference
+            "RFC 2863: The Interfaces Group MIB - ifOutDiscards";
+        }
+        leaf out-errors {
+          type yang:counter32;
+          description
+            "For packet-oriented interfaces, the number of outbound
+             packets that could not be transmitted because of errors.
+             For character-oriented or fixed-length interfaces, the
+             number of outbound transmission units that could not be
+             transmitted because of errors.
+
+             Discontinuities in the value of this counter can occur
+             at re-initialization of the management system, and at
+             other times as indicated by the value of
+             'discontinuity-time'.";
+          reference
+            "RFC 2863: The Interfaces Group MIB - ifOutErrors";
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/ietf-restconf@2013-10-19.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/ietf-restconf@2013-10-19.yang
new file mode 100644 (file)
index 0000000..16766b0
--- /dev/null
@@ -0,0 +1,684 @@
+module ietf-restconf {
+     namespace "urn:ietf:params:xml:ns:yang:ietf-restconf";
+     prefix "restconf";
+
+     import ietf-yang-types { prefix yang; }
+     import ietf-inet-types { prefix inet; }
+     organization
+       "IETF NETCONF (Network Configuration) Working Group";
+
+     contact
+       "Editor:   Andy Bierman
+                  <mailto:andy@yumaworks.com>
+
+        Editor:   Martin Bjorklund
+                  <mailto:mbj@tail-f.com>
+
+        Editor:   Kent Watsen
+                  <mailto:kwatsen@juniper.net>
+
+        Editor:   Rex Fernando
+                  <mailto:rex@cisco.com>";
+
+     description
+       "This module contains conceptual YANG specifications
+        for the YANG Patch and error content that is used in
+        RESTCONF protocol messages. A conceptual container
+        representing the RESTCONF API nodes (media type
+        application/yang.api).
+
+        Note that the YANG definitions within this module do not
+        represent configuration data of any kind.
+        The YANG grouping statements provide a normative syntax
+        for XML and JSON message encoding purposes.
+        Copyright (c) 2013 IETF Trust and the persons identified as
+        authors of the code.  All rights reserved.
+
+        Redistribution and use in source and binary forms, with or
+        without modification, is permitted pursuant to, and subject
+        to the license terms contained in, the Simplified BSD License
+        set forth in Section 4.c of the IETF Trust's Legal Provisions
+        Relating to IETF Documents
+        (http://trustee.ietf.org/license-info).
+
+        This version of this YANG module is part of RFC XXXX; see
+        the RFC itself for full legal notices.";
+
+     // RFC Ed.: replace XXXX with actual RFC number and remove this
+     // note.
+
+     // RFC Ed.: remove this note
+     // Note: extracted from draft-bierman-netconf-restconf-02.txt
+
+     // RFC Ed.: update the date below with the date of RFC publication
+     // and remove this note.
+     revision 2013-10-19 {
+       description
+         "Initial revision.";
+       reference
+         "RFC XXXX: RESTCONF Protocol.";
+     }
+
+     typedef data-resource-identifier {
+       type string {
+         length "1 .. max";
+       }
+       description
+         "Contains a Data Resource Identifier formatted string
+          to identify a specific data node. The data node that
+          uses this data type SHOULD define the document root
+          for data resource identifiers.  The default document
+          root is the target datastore conceptual root node.
+          Data resource identifiers are defined relative to
+          this document root.";
+       reference
+         "RFC XXXX: [sec. 5.3.1.1 ABNF For Data Resource Identifiers]";
+     }
+
+     // this typedef is TBD; not currently used
+     typedef datastore-identifier {
+       type union {
+         type enumeration {
+           enum candidate {
+             description
+               "Identifies the NETCONF shared candidate datastore.";
+             reference
+               "RFC 6241, section 8.3";
+           }
+           enum running {
+             description
+               "Identifies the NETCONF running datastore.";
+             reference
+               "RFC 6241, section 5.1";
+           }
+           enum startup {
+             description
+               "Identifies the NETCONF startup datastore.";
+             reference
+               "RFC 6241, section 8.7";
+           }
+         }
+         type string;
+       }
+       description
+         "Contains a string to identify a specific datastore.
+          The enumerated datastore identifier values are
+          reserved for standard datastore names.";
+     }
+
+     typedef revision-identifier {
+       type string {
+         pattern '\d{4}-\d{2}-\d{2}';
+       }
+       description
+         "Represents a specific date in YYYY-MM-DD format.
+          TBD: make pattern more precise to exclude leading zeros.";
+     }
+
+     grouping yang-patch {
+       description
+         "A grouping that contains a YANG container
+          representing the syntax and semantics of a
+          YANG Patch edit request message.";
+
+       container yang-patch {
+         description
+           "Represents a conceptual sequence of datastore edits,
+            called a patch. Each patch is given a client-assigned
+            patch identifier. Each edit MUST be applied
+            in ascending order, and all edits MUST be applied.
+            If any errors occur, then the target datastore MUST NOT
+            be changed by the patch operation.
+
+            A patch MUST be validated by the server to be a
+            well-formed message before any of the patch edits
+            are validated or attempted.
+
+            YANG datastore validation (defined in RFC 6020, section 
+            8.3.3) is performed after all edits have been
+            individually validated.
+
+            It is possible for a datastore constraint violation to occur
+            due to any node in the datastore, including nodes not
+            included in the edit list. Any validation errors MUST
+            be reported in the reply message.";
+
+         reference
+           "RFC 6020, section 8.3.";
+
+         leaf patch-id {
+           type string;
+           description
+             "An arbitrary string provided by the client to identify
+              the entire patch.  This value SHOULD be present in any
+              audit logging records generated by the server for the
+              patch. Error messages returned by the server pertaining
+              to this patch will be identified by this patch-id value.";
+         }
+
+         leaf comment {
+           type string {
+             length "0 .. 1024";
+           }
+           description
+             "An arbitrary string provided by the client to describe
+              the entire patch.  This value SHOULD be present in any
+              audit logging records generated by the server for the
+              patch.";
+         }
+
+         list edit {
+           key edit-id;
+           ordered-by user;
+
+           description
+             "Represents one edit within the YANG Patch
+              request message.";
+           leaf edit-id {
+             type string;
+             description
+               "Arbitrary string index for the edit.
+                Error messages returned by the server pertaining
+                to a specific edit will be identified by this
+                value.";
+           }
+
+           leaf operation {
+             type enumeration {
+               enum create {
+                 description
+                   "The target data node is created using the
+                    supplied value, only if it does not already
+                    exist.";
+               }
+               enum delete {
+                 description
+                   "Delete the target node, only if the data resource
+                    currently exists, otherwise return an error.";
+               }
+               enum insert {
+                 description
+                   "Insert the supplied value into a user-ordered
+                    list or leaf-list entry. The target node must
+                    represent a new data resource.";
+               }
+               enum merge {
+                 description
+                   "The supplied value is merged with the target data
+                    node.";
+               }
+               enum move {
+                 description
+                   "Move the target node. Reorder a user-ordered
+                    list or leaf-list. The target node must represent
+                    an existing data resource.";
+               }
+               enum replace {
+                 description
+                   "The supplied value is used to replace the target
+                    data node.";
+               }
+               enum remove {
+                 description
+                   "Delete the target node if it currently exists.";
+               }
+             }
+             mandatory true;
+             description
+               "The datastore operation requested for the associated
+                edit entry";
+           }
+
+           leaf target {
+             type data-resource-identifier;
+             mandatory true;
+             description
+               "Identifies the target data resource for the edit
+                operation.";
+           }
+
+           leaf point {
+             when "(../operation = 'insert' or " +
+               "../operation = 'move') and " +
+               "(../where = 'before' or ../where = 'after')" {
+               description
+                 "Point leaf only applies for insert or move
+                  operations, before or after an existing entry.";
+             }
+             type data-resource-identifier;
+             description
+               "The absolute URL path for the data node that is being
+                used as the insertion point or move point for the
+                target of this edit entry.";
+           }
+
+           leaf where {
+             when "../operation = 'insert' or ../operation = 'move'" {
+               description
+                 "Where leaf only applies for insert or move
+                  operations.";
+             }
+             type enumeration {
+               enum before {
+                 description
+                   "Insert or move a data node before the data resource
+                    identified by the 'point' parameter.";
+               }
+               enum after {
+                 description
+                   "Insert or move a data node after the data resource
+                    identified by the 'point' parameter.";
+               }
+               enum first {
+                 description
+                   "Insert or move a data node so it becomes ordered
+                    as the first entry.";
+               }
+               enum last {
+                 description
+                   "Insert or move a data node so it becomes ordered
+                    as the last entry.";
+               }
+
+             }
+             default last;
+             description
+               "Identifies where a data resource will be inserted or
+                moved. YANG only allows these operations for
+                list and leaf-list data nodes that are ordered-by
+                user.";
+           }
+
+           anyxml value {
+             when "(../operation = 'create' or " +
+               "../operation = 'merge' " +
+               "or ../operation = 'replace' or " +
+               "../operation = 'insert')" {
+               description
+                 "Value node only used for create, merge,
+                  replace, and insert operations";
+             }
+             description
+               "Value used for this edit operation.";
+           }
+         }
+       }
+
+     } // grouping yang-patch
+
+
+     grouping yang-patch-status {
+
+       description
+         "A grouping that contains a YANG container
+          representing the syntax and semantics of
+          YANG Patch status response message.";
+
+       container yang-patch-status {
+         description
+           "A container representing the response message
+            sent by the server after a YANG Patch edit
+            request message has been processed.";
+
+         leaf patch-id {
+           type string;
+           description
+             "The patch-id value used in the request";
+         }
+
+         choice global-status {
+           description
+             "Report global errors or complete success.
+              If there is no case selected then errors
+              are reported in the edit-status container.";
+
+           case global-errors {
+             uses errors;
+             description
+               "This container will be present if global
+                errors unrelated to a specific edit occurred.";
+           }
+           leaf ok {
+             type empty;
+             description
+               "This leaf will be present if the request succeeded
+                and there are no errors reported in the edit-status
+                container.";
+           }
+         }
+
+         container edit-status {
+           description
+             "This container will be present if there are
+              edit-specific status responses to report.";
+
+           list edit {
+             key edit-id;
+
+             description
+               "Represents a list of status responses,
+                corresponding to edits in the YANG Patch
+                request message.  If an edit entry was
+                skipped or not reached by the server,
+                then this list will not contain a corresponding
+                entry for that edit.";
+
+             leaf edit-id {
+               type string;
+                description
+                  "Response status is for the edit list entry
+                   with this edit-id value.";
+             }
+             choice edit-status-choice {
+               description
+                 "A choice between different types of status
+                  responses for each edit entry.";
+               leaf ok {
+                 type empty;
+                 description
+                   "This edit entry was invoked without any
+                    errors detected by the server associated
+                    with this edit.";
+               }
+               leaf location {
+                 type inet:uri;
+                 description
+                   "Contains the Location header value that would be
+                    returned if this edit causes a new resource to be
+                    created. If the edit identified by the same edit-id
+                    value was successfully invoked and a new resource
+                    was created, then this field will be returned
+                    instead of 'ok'.";
+               }
+               case errors {
+                 uses errors;
+                 description
+                   "The server detected errors associated with the
+                     edit identified by the same edit-id value.";
+               }
+             }
+           }
+         }
+       }
+     }  // grouping yang-patch-status
+
+
+     grouping errors {
+
+       description
+         "A grouping that contains a YANG container
+          representing the syntax and semantics of a
+          YANG Patch errors report within a response message.";
+
+       container errors {
+         config false;  // needed so list error does not need a key
+         description
+           "Represents an error report returned by the server if
+            a request results in an error.";
+
+         list error {
+           description
+             "An entry containing information about one
+              specific error that occurred while processing
+              a RESTCONF request.";
+           reference "RFC 6241, Section 4.3";
+
+           leaf error-type {
+             type enumeration {
+               enum transport {
+                 description "The transport layer";
+               }
+               enum rpc {
+                 description "The rpc or notification layer";
+               }
+               enum protocol {
+                 description "The protocol operation layer";
+               }
+               enum application {
+                 description "The server application layer";
+               }
+             }
+             mandatory true;
+             description
+               "The protocol layer where the error occurred.";
+           }
+
+           leaf error-tag {
+             type string;
+             mandatory true;
+             description
+               "The enumerated error tag.";
+           }
+
+           leaf error-app-tag {
+             type string;
+             description
+               "The application-specific error tag.";
+           }
+
+           leaf error-path {
+             type data-resource-identifier;
+             description
+               "The target data resource identifier associated
+                with the error, if any.";
+           }
+           leaf error-message {
+             type string;
+             description
+               "A message describing the error.";
+           }
+
+           container error-info {
+              description
+                "A container allowing additional information
+                 to be included in the error report.";
+              // arbitrary anyxml content here
+           }
+         }
+       }
+     } // grouping errors
+
+
+     grouping restconf {
+
+       description
+         "A grouping that contains a YANG container
+          representing the syntax and semantics of
+          the RESTCONF API resource.";
+
+       container restconf {
+         description
+           "Conceptual container representing the
+            application/yang.api resource type.";
+
+         container config {
+           description
+             "Container representing the application/yang.datastore
+              resource type. Represents the conceptual root of the
+              unified configuration datastore containing YANG data
+              nodes. The child nodes of this container are
+              configuration data resources (application/yang.data)
+              defined as top-level YANG data nodes from the modules
+              advertised by the server in /restconf/modules.";
+         }
+
+         container operational {
+           description
+             "Container representing the application/yang.datastore
+              resource type. Represents the conceptual root of the
+              operational data supported by the server.  The child
+              nodes of this container are operational data resources
+              (application/yang.data) defined as top-level
+              YANG data nodes from the modules advertised by
+              the server in /restconf/modules.";
+         }
+
+         container modules {
+           description
+             "Contains a list of module description entries.
+              These modules are currently loaded into the server.";
+
+           list module {
+             key "name revision";
+             description
+               "Each entry represents one module currently
+                supported by the server.";
+
+             leaf name {
+               type yang:yang-identifier;
+               description "The YANG module name.";
+             }
+             leaf revision {
+               type union {
+                 type revision-identifier;
+                 type string { length 0; }
+               }
+               description
+                 "The YANG module revision date. An empty string is
+                  used if no revision statement is present in the
+                  YANG module.";
+             }
+             leaf namespace {
+               type inet:uri;
+               mandatory true;
+               description
+                 "The XML namespace identifier for this module.";
+             }
+             leaf-list feature {
+               type yang:yang-identifier;
+               description
+                 "List of YANG feature names from this module that are
+                  supported by the server.";
+             }
+             leaf-list deviation {
+               type yang:yang-identifier;
+               description
+                 "List of YANG deviation module names used by this
+                  server to modify the conformance of the module
+                  associated with this entry.";
+             }
+           }
+         }
+
+         container operations {
+           description
+             "Container for all operation resources
+              (application/yang.operation),
+
+              Each resource is represented as an empty leaf with the
+              name of the RPC operation from the YANG rpc statement.
+
+              E.g.;
+
+                 POST /restconf/operations/show-log-errors
+
+                 leaf show-log-errors {
+                   type empty;
+                 }
+             ";
+         }
+
+         container streams {
+           description
+             "Container representing the notification event streams
+              supported by the server.";
+            reference
+              "RFC 5277, Section 3.4, <streams> element.";
+
+           list stream {
+             key name;
+             description
+               "Each entry describes an event stream supported by
+                the server.";
+
+             leaf name {
+               type string;
+               description "The stream name";
+               reference "RFC 5277, Section 3.4, <name> element.";
+             }
+
+             leaf description {
+               type string;
+               description "Description of stream content";
+               reference
+                 "RFC 5277, Section 3.4, <description> element.";
+             }
+
+             leaf replay-support {
+               type boolean;
+               description
+                 "Indicates if replay buffer supported for this stream";
+               reference
+                 "RFC 5277, Section 3.4, <replaySupport> element.";
+             }
+
+             leaf replay-log-creation-time {
+               type yang:date-and-time;
+               description
+                 "Indicates the time the replay log for this stream
+                  was created.";
+               reference
+                 "RFC 5277, Section 3.4, <replayLogCreationTime>
+                  element.";
+             }
+
+             leaf events {
+               type empty;
+               description
+                 "Represents the entry point for establishing
+                  notification delivery via server sent events.";
+             }
+           }
+         }
+
+         leaf version {
+           type enumeration {
+             enum "1.0" {
+               description
+                 "Version 1.0 of the RESTCONF protocol.";
+             }
+           }
+           config false;
+           description
+             "Contains the RESTCONF protocol version.";
+         }
+       }
+     }  // grouping restconf
+
+
+     grouping notification {
+       description
+         "Contains the notification message wrapper definition.";
+
+       container notification {
+         description
+           "RESTCONF notification message wrapper.";
+         leaf event-time {
+           type yang:date-and-time;
+           mandatory true;
+           description
+             "The time the event was generated by the
+              event source.";
+           reference
+             "RFC 5277, section 4, <eventTime> element.";
+         }
+
+         /* The YANG-specific notification container is encoded
+          * after the 'event-time' element.  The format
+          * corresponds to the notificationContent element
+          * in RFC 5277, section 4. For example:
+          *
+          *  module example-one {
+          *     ...
+          *     notification event1 { ... }
+          *
+          *  }
+          *
+          *  Encoded as element 'event1' in the namespace
+          *  for module 'example-one'.
+          */
+       }
+     }  // grouping notification
+
+   }
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/ietf-yang-types.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/ietf-yang-types.yang
new file mode 100644 (file)
index 0000000..07e50b3
--- /dev/null
@@ -0,0 +1,417 @@
+ module ietf-yang-types {
+
+   namespace "urn:ietf:params:xml:ns:yang:ietf-yang-types";
+   prefix "yang";
+
+   organization
+    "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+   contact
+    "WG Web:   <http://tools.ietf.org/wg/netmod/>
+     WG List:  <mailto:netmod@ietf.org>
+
+     WG Chair: David Partain
+               <mailto:david.partain@ericsson.com>
+
+     WG Chair: David Kessens
+               <mailto:david.kessens@nsn.com>
+
+     Editor:   Juergen Schoenwaelder
+               <mailto:j.schoenwaelder@jacobs-university.de>";
+
+   description
+    "This module contains a collection of generally useful derived
+     YANG data types.
+
+     Copyright (c) 2010 IETF Trust and the persons identified as
+     authors of the code.  All rights reserved.
+
+     Redistribution and use in source and binary forms, with or without
+     modification, is permitted pursuant to, and subject to the license
+     terms contained in, the Simplified BSD License set forth in Section
+     4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
+     (http://trustee.ietf.org/license-info).
+
+     This version of this YANG module is part of RFC 6021; see
+     the RFC itself for full legal notices.";
+
+   revision 2010-09-24 {
+     description
+      "Initial revision.";
+     reference
+      "RFC 6021: Common YANG Data Types";
+   }
+
+   /*** collection of counter and gauge types ***/
+
+   typedef counter32 {
+     type uint32;
+     description
+      "The counter32 type represents a non-negative integer
+       that monotonically increases until it reaches a
+       maximum value of 2^32-1 (4294967295 decimal), when it
+       wraps around and starts increasing again from zero.
+
+       Counters have no defined 'initial' value, and thus, a
+       single value of a counter has (in general) no information
+       content.  Discontinuities in the monotonically increasing
+       value normally occur at re-initialization of the
+       management system, and at other times as specified in the
+       description of a schema node using this type.  If such
+       other times can occur, for example, the creation of
+       a schema node of type counter32 at times other than
+       re-initialization, then a corresponding schema node
+       should be defined, with an appropriate type, to indicate
+       the last discontinuity.
+
+       The counter32 type should not be used for configuration
+       schema nodes.  A default statement SHOULD NOT be used in
+       combination with the type counter32.
+
+       In the value set and its semantics, this type is equivalent
+       to the Counter32 type of the SMIv2.";
+     reference
+      "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+   }
+
+   typedef zero-based-counter32 {
+     type yang:counter32;
+     default "0";
+     description
+      "The zero-based-counter32 type represents a counter32
+       that has the defined 'initial' value zero.
+
+       A schema node of this type will be set to zero (0) on creation
+       and will thereafter increase monotonically until it reaches
+       a maximum value of 2^32-1 (4294967295 decimal), when it
+       wraps around and starts increasing again from zero.
+
+       Provided that an application discovers a new schema node
+       of this type within the minimum time to wrap, it can use the
+       'initial' value as a delta.  It is important for a management
+       station to be aware of this minimum time and the actual time
+       between polls, and to discard data if the actual time is too
+       long or there is no defined minimum time.
+
+       In the value set and its semantics, this type is equivalent
+       to the ZeroBasedCounter32 textual convention of the SMIv2.";
+     reference
+       "RFC 4502: Remote Network Monitoring Management Information
+                  Base Version 2";
+   }
+
+   typedef counter64 {
+     type uint64;
+     description
+      "The counter64 type represents a non-negative integer
+       that monotonically increases until it reaches a
+       maximum value of 2^64-1 (18446744073709551615 decimal),
+       when it wraps around and starts increasing again from zero.
+
+       Counters have no defined 'initial' value, and thus, a
+       single value of a counter has (in general) no information
+       content.  Discontinuities in the monotonically increasing
+       value normally occur at re-initialization of the
+       management system, and at other times as specified in the
+       description of a schema node using this type.  If such
+       other times can occur, for example, the creation of
+       a schema node of type counter64 at times other than
+       re-initialization, then a corresponding schema node
+       should be defined, with an appropriate type, to indicate
+       the last discontinuity.
+
+       The counter64 type should not be used for configuration
+       schema nodes.  A default statement SHOULD NOT be used in
+       combination with the type counter64.
+
+       In the value set and its semantics, this type is equivalent
+       to the Counter64 type of the SMIv2.";
+     reference
+      "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+   }
+
+   typedef zero-based-counter64 {
+     type yang:counter64;
+     default "0";
+     description
+      "The zero-based-counter64 type represents a counter64 that
+       has the defined 'initial' value zero.
+
+       A schema node of this type will be set to zero (0) on creation
+       and will thereafter increase monotonically until it reaches
+       a maximum value of 2^64-1 (18446744073709551615 decimal),
+       when it wraps around and starts increasing again from zero.
+
+       Provided that an application discovers a new schema node
+       of this type within the minimum time to wrap, it can use the
+       'initial' value as a delta.  It is important for a management
+       station to be aware of this minimum time and the actual time
+       between polls, and to discard data if the actual time is too
+       long or there is no defined minimum time.
+
+       In the value set and its semantics, this type is equivalent
+       to the ZeroBasedCounter64 textual convention of the SMIv2.";
+     reference
+      "RFC 2856: Textual Conventions for Additional High Capacity
+                 Data Types";
+   }
+
+   typedef gauge32 {
+     type uint32;
+     description
+      "The gauge32 type represents a non-negative integer, which
+       may increase or decrease, but shall never exceed a maximum
+       value, nor fall below a minimum value.  The maximum value
+       cannot be greater than 2^32-1 (4294967295 decimal), and
+       the minimum value cannot be smaller than 0.  The value of
+       a gauge32 has its maximum value whenever the information
+       being modeled is greater than or equal to its maximum
+       value, and has its minimum value whenever the information
+       being modeled is smaller than or equal to its minimum value.
+       If the information being modeled subsequently decreases
+       below (increases above) the maximum (minimum) value, the
+       gauge32 also decreases (increases).
+
+       In the value set and its semantics, this type is equivalent
+       to the Gauge32 type of the SMIv2.";
+     reference
+      "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+   }
+
+   typedef gauge64 {
+     type uint64;
+     description
+      "The gauge64 type represents a non-negative integer, which
+       may increase or decrease, but shall never exceed a maximum
+       value, nor fall below a minimum value.  The maximum value
+       cannot be greater than 2^64-1 (18446744073709551615), and
+       the minimum value cannot be smaller than 0.  The value of
+       a gauge64 has its maximum value whenever the information
+       being modeled is greater than or equal to its maximum
+       value, and has its minimum value whenever the information
+       being modeled is smaller than or equal to its minimum value.
+       If the information being modeled subsequently decreases
+       below (increases above) the maximum (minimum) value, the
+       gauge64 also decreases (increases).
+
+       In the value set and its semantics, this type is equivalent
+       to the CounterBasedGauge64 SMIv2 textual convention defined
+       in RFC 2856";
+     reference
+      "RFC 2856: Textual Conventions for Additional High Capacity
+                 Data Types";
+   }
+
+   /*** collection of identifier related types ***/
+
+   typedef object-identifier {
+     type string {
+       pattern '(([0-1](\.[1-3]?[0-9]))|(2\.(0|([1-9]\d*))))'
+             + '(\.(0|([1-9]\d*)))*';
+     }
+     description
+      "The object-identifier type represents administratively
+       assigned names in a registration-hierarchical-name tree.
+
+       Values of this type are denoted as a sequence of numerical
+       non-negative sub-identifier values.  Each sub-identifier
+       value MUST NOT exceed 2^32-1 (4294967295).  Sub-identifiers
+       are separated by single dots and without any intermediate
+       whitespace.
+
+       The ASN.1 standard restricts the value space of the first
+       sub-identifier to 0, 1, or 2.  Furthermore, the value space
+       of the second sub-identifier is restricted to the range
+       0 to 39 if the first sub-identifier is 0 or 1.  Finally,
+       the ASN.1 standard requires that an object identifier
+       has always at least two sub-identifier.  The pattern
+       captures these restrictions.
+
+       Although the number of sub-identifiers is not limited,
+       module designers should realize that there may be
+       implementations that stick with the SMIv2 limit of 128
+       sub-identifiers.
+
+       This type is a superset of the SMIv2 OBJECT IDENTIFIER type
+       since it is not restricted to 128 sub-identifiers.  Hence,
+       this type SHOULD NOT be used to represent the SMIv2 OBJECT
+       IDENTIFIER type, the object-identifier-128 type SHOULD be
+       used instead.";
+     reference
+      "ISO9834-1: Information technology -- Open Systems
+       Interconnection -- Procedures for the operation of OSI
+       Registration Authorities: General procedures and top
+       arcs of the ASN.1 Object Identifier tree";
+   }
+
+
+
+
+   typedef object-identifier-128 {
+     type object-identifier {
+       pattern '\d*(\.\d*){1,127}';
+     }
+     description
+      "This type represents object-identifiers restricted to 128
+       sub-identifiers.
+
+       In the value set and its semantics, this type is equivalent
+       to the OBJECT IDENTIFIER type of the SMIv2.";
+     reference
+      "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+   }
+   
+    typedef yang-identifier {
+       type string {
+         length "1..max";
+         pattern '[a-zA-Z_][a-zA-Z0-9\-_.]*';
+         pattern '.|..|[^xX].*|.[^mM].*|..[^lL].*';
+       }
+       description
+         "A YANG identifier string as defined by the 'identifier'
+          rule in Section 12 of RFC 6020.  An identifier must
+          start with an alphabetic character or an underscore
+          followed by an arbitrary sequence of alphabetic or
+          numeric characters, underscores, hyphens, or dots.
+
+          A YANG identifier MUST NOT start with any possible
+          combination of the lowercase or uppercase character
+          sequence 'xml'.";
+       reference
+         "RFC 6020: YANG - A Data Modeling Language for the Network
+                    Configuration Protocol (NETCONF)";
+     }   
+
+   /*** collection of date and time related types ***/
+
+   typedef date-and-time {
+     type string {
+       pattern '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?'
+             + '(Z|[\+\-]\d{2}:\d{2})';
+     }
+     description
+      "The date-and-time type is a profile of the ISO 8601
+       standard for representation of dates and times using the
+       Gregorian calendar.  The profile is defined by the
+       date-time production in Section 5.6 of RFC 3339.
+
+       The date-and-time type is compatible with the dateTime XML
+       schema type with the following notable exceptions:
+
+       (a) The date-and-time type does not allow negative years.
+
+       (b) The date-and-time time-offset -00:00 indicates an unknown
+           time zone (see RFC 3339) while -00:00 and +00:00 and Z all
+           represent the same time zone in dateTime.
+
+       (c) The canonical format (see below) of data-and-time values
+           differs from the canonical format used by the dateTime XML
+           schema type, which requires all times to be in UTC using the
+           time-offset 'Z'.
+
+       This type is not equivalent to the DateAndTime textual
+       convention of the SMIv2 since RFC 3339 uses a different
+       separator between full-date and full-time and provides
+       higher resolution of time-secfrac.
+
+       The canonical format for date-and-time values with a known time
+       zone uses a numeric time zone offset that is calculated using
+       the device's configured known offset to UTC time.  A change of
+       the device's offset to UTC time will cause date-and-time values
+       to change accordingly.  Such changes might happen periodically
+       in case a server follows automatically daylight saving time
+       (DST) time zone offset changes.  The canonical format for
+       date-and-time values with an unknown time zone (usually referring
+       to the notion of local time) uses the time-offset -00:00.";
+     reference
+      "RFC 3339: Date and Time on the Internet: Timestamps
+       RFC 2579: Textual Conventions for SMIv2
+       XSD-TYPES: XML Schema Part 2: Datatypes Second Edition";
+   }
+
+   typedef timeticks {
+     type uint32;
+     description
+      "The timeticks type represents a non-negative integer that
+       represents the time, modulo 2^32 (4294967296 decimal), in
+       hundredths of a second between two epochs.  When a schema
+       node is defined that uses this type, the description of
+       the schema node identifies both of the reference epochs.
+
+       In the value set and its semantics, this type is equivalent
+       to the TimeTicks type of the SMIv2.";
+     reference
+      "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+   }
+
+   typedef timestamp {
+     type yang:timeticks;
+     description
+      "The timestamp type represents the value of an associated
+       timeticks schema node at which a specific occurrence happened.
+       The specific occurrence must be defined in the description
+       of any schema node defined using this type.  When the specific
+       occurrence occurred prior to the last time the associated
+       timeticks attribute was zero, then the timestamp value is
+       zero.  Note that this requires all timestamp values to be
+       reset to zero when the value of the associated timeticks
+       attribute reaches 497+ days and wraps around to zero.
+
+       The associated timeticks schema node must be specified
+       in the description of any schema node using this type.
+
+       In the value set and its semantics, this type is equivalent
+       to the TimeStamp textual convention of the SMIv2.";
+     reference
+      "RFC 2579: Textual Conventions for SMIv2";
+   }
+
+   /*** collection of generic address types ***/
+
+   typedef phys-address {
+     type string {
+       pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?';
+     }
+     description
+      "Represents media- or physical-level addresses represented
+       as a sequence octets, each octet represented by two hexadecimal
+       numbers.  Octets are separated by colons.  The canonical
+       representation uses lowercase characters.
+
+       In the value set and its semantics, this type is equivalent
+       to the PhysAddress textual convention of the SMIv2.";
+     reference
+      "RFC 2579: Textual Conventions for SMIv2";
+   }
+
+   typedef mac-address {
+     type string {
+       pattern '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}';
+     }
+     description
+      "The mac-address type represents an IEEE 802 MAC address.
+       The canonical representation uses lowercase characters.
+
+       In the value set and its semantics, this type is equivalent
+       to the MacAddress textual convention of the SMIv2.";
+     reference
+      "IEEE 802: IEEE Standard for Local and Metropolitan Area
+                 Networks: Overview and Architecture
+       RFC 2579: Textual Conventions for SMIv2";
+   }
+
+   /*** collection of XML specific types ***/
+
+   typedef xpath1.0 {
+     type string;
+     description
+      "This type represents an XPATH 1.0 expression.
+
+       When a schema node is defined that uses this type, the
+       description of the schema node MUST specify the XPath
+       context in which the XPath expression is evaluated.";
+     reference
+      "XPATH: XML Path Language (XPath) Version 1.0";
+   }
+
+ }
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/module1.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/module1.yang
new file mode 100644 (file)
index 0000000..604fe94
--- /dev/null
@@ -0,0 +1,12 @@
+module module1 {
+    namespace "module:1";
+    prefix "mod1";
+    revision "2014-01-01";
+    
+    rpc dummy-rpc1-module1 {
+    }
+    
+    rpc dummy-rpc2-module1 {
+    }
+    
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/module2.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/module2.yang
new file mode 100644 (file)
index 0000000..7b359f3
--- /dev/null
@@ -0,0 +1,11 @@
+module module2 {
+    namespace "module:2";
+    prefix "mod2";
+    revision "2014-01-02";
+    
+    rpc dummy-rpc1-module2 {
+    }
+    
+    rpc dummy-rpc2-module2 {
+    }    
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/module3.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/module3.yang
new file mode 100644 (file)
index 0000000..39bb690
--- /dev/null
@@ -0,0 +1,5 @@
+module module3 {
+    namespace "module:3";
+    prefix "mod3";
+    revision "2014-01-03";
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/modules-behind-mount-point/module1-behind-mount-point.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/modules-behind-mount-point/module1-behind-mount-point.yang
new file mode 100644 (file)
index 0000000..e48184b
--- /dev/null
@@ -0,0 +1,10 @@
+module module1-behind-mount-point {
+    namespace "module:1:behind:mount:point";
+    prefix "mod1bemopo";
+    revision "2014-02-03";
+    
+    rpc rpc-behind-module1 {
+    }
+    
+    
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/modules-behind-mount-point/module2-behind-mount-point.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/modules-behind-mount-point/module2-behind-mount-point.yang
new file mode 100644 (file)
index 0000000..89b8c02
--- /dev/null
@@ -0,0 +1,9 @@
+module module2-behind-mount-point {
+    namespace "module:2:behind:mount:point";
+    prefix "mod2bemopo";
+    revision "2014-02-04";
+    
+    rpc rpc-behind-module2 {
+    }
+    
+}
\ No newline at end of file
index 8294c101e977e7d51bb12af5a47d6e6327ca893d..8159707d57dd4e7cf3010f1aa6678af62cc52a4c 100644 (file)
@@ -6,47 +6,87 @@
         <version>1.1-SNAPSHOT</version>
     </parent>
     <artifactId>sal-restconf-broker</artifactId>
-    <packaging>jar</packaging>
+    <packaging>bundle</packaging>
     <scm>
         <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
         <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
         <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
       <tag>HEAD</tag>
   </scm>
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-bundle-plugin</artifactId>
-                <extensions>true</extensions>
-            </plugin>
-        </plugins>
-    </build>
-
     <dependencies>
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>sal-binding-api</artifactId>
-            <version>1.1-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-util</artifactId>
         </dependency>
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>sal-remote</artifactId>
-            <version>1.1-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-broker-impl</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal-binding-config</artifactId>
         </dependency>
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>sal-core-api</artifactId>
-            <version>1.1-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>restconf-client-api</artifactId>
             <version>${yangtools.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>restconf-client-impl</artifactId>
+            <version>${yangtools.version}</version>
+        </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
         </dependency>
     </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+                        <Import-Package>
+                                *
+                        </Import-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <version>1.8</version>
+                <executions>
+                    <execution>
+                        <id>add-source</id>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>add-source</goal>
+                        </goals>
+                        <configuration>
+                            <sources>
+                                <source>${project.build.directory}/generated-sources/</source>
+                            </sources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
 </project>
diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationServiceImpl.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationServiceImpl.java
deleted file mode 100644 (file)
index 76c98e3..0000000
+++ /dev/null
@@ -1,47 +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.binding.impl;
-
-import org.opendaylight.controller.sal.binding.api.NotificationListener;
-import org.opendaylight.controller.sal.binding.api.NotificationService;
-import org.opendaylight.yangtools.concepts.Registration;
-import org.opendaylight.yangtools.yang.binding.Notification;
-
-public class NotificationServiceImpl implements NotificationService {
-    @Override
-    public <T extends Notification> void addNotificationListener(Class<T> notificationType, NotificationListener<T> listener) {
-
-    }
-
-    @Override
-    public void addNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) {
-
-    }
-
-    @Override
-    public void removeNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) {
-
-    }
-
-    @Override
-    public <T extends Notification> void removeNotificationListener(Class<T> notificationType, NotificationListener<T> listener) {
-
-    }
-
-    @Override
-    public <T extends Notification> Registration<NotificationListener<T>> registerNotificationListener(Class<T> notificationType, NotificationListener<T> listener) {
-        //TODO implementation using sal-remote
-        return null;
-    }
-
-    @Override
-    public Registration<org.opendaylight.yangtools.yang.binding.NotificationListener> registerNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) {
-        //TODO implementation using sal-remote
-        return null;
-    }
-}
@@ -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.sal.binding.impl;
+package org.opendaylight.controller.sal.restconf.binding.impl;
 
 import java.net.URL;
 import java.util.concurrent.Future;
@@ -21,6 +21,8 @@ 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;
 import org.slf4j.LoggerFactory;
 
@@ -30,8 +32,8 @@ public class DataBrokerServiceImpl implements DataBrokerService {
     private final RestconfClientContext restconfClientContext;
     private final RestconfClientContextFactory restconfClientContextFactory = null;
 
-    public DataBrokerServiceImpl(URL baseUrl) throws UnsupportedProtocolException {
-        this.restconfClientContext = restconfClientContextFactory.getRestconfClientContext(baseUrl);
+    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) {
index 988bfd8ca51da148d0979b9eb06941368ba2ace3..74b23201e74bd645e132843664b8897bc6943d6c 100644 (file)
@@ -8,25 +8,60 @@
 package org.opendaylight.controller.sal.restconf.broker;
 
 
-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 com.google.common.collect.ImmutableClassToInstanceMap;
+import org.opendaylight.controller.md.sal.binding.util.BindingContextUtils;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer;
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.opendaylight.controller.sal.binding.api.BindingAwareService;
+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.restconf.broker.impl.RemoteServicesFactory;
+import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext;
 import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import static com.google.common.base.Preconditions.checkState;
 
-public class SalRemoteServiceBroker implements Broker,AutoCloseable {
+public class SalRemoteServiceBroker implements BindingAwareBroker,AutoCloseable {
 
-    @Override
-    public void close() throws Exception {
 
+    private static final Logger logger = LoggerFactory.getLogger(SalRemoteServiceBroker.class.toString());
+    private ImmutableClassToInstanceMap<BindingAwareService> supportedConsumerServices;
+
+    private final String identifier;
+
+    private RpcConsumerRegistry rpcBroker;
+    private NotificationService notificationBroker;
+    private DataBrokerService dataBroker;
+    private final RemoteServicesFactory servicesFactory;
+
+    public SalRemoteServiceBroker(String instanceName,RestconfClientContext clientContext){
+        this.identifier = instanceName;
+        this.servicesFactory = new RemoteServicesFactory(clientContext);
     }
 
-    @Override
-    public ConsumerSession registerConsumer(Consumer cons, BundleContext context) {
-        return null;
+    public void start() {
+        logger.info("Starting Binding Aware Broker: {}", identifier);
+
+        supportedConsumerServices = ImmutableClassToInstanceMap.<BindingAwareService> builder()
+                .put(NotificationService.class, servicesFactory.getNotificationService()) //
+                .put(DataBrokerService.class,servicesFactory.getDataBrokerService() ) //
+                .put(RpcConsumerRegistry.class,servicesFactory.getRpcConsumerRegistry() ).build();
     }
 
+    public ProviderContext registerProvider(BindingAwareProvider provider, BundleContext ctx) {
+        throw new UnsupportedOperationException();
+    }
+    @Override
+    public void close() throws Exception {
+        //TODO decide if serviceFactory should close clientContext or it has to be closed by consumer
+    }
     @Override
-    public ProviderSession registerProvider(Provider prov, BundleContext context) {
-        return null;
+    public ConsumerContext registerConsumer(BindingAwareConsumer consumer, BundleContext ctx) {
+        checkState(supportedConsumerServices != null, "Broker is not initialized.");
+        return BindingContextUtils.createConsumerContextAndInitialize(consumer, supportedConsumerServices);
     }
+
 }
diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/event/RemoteDataChangeEvent.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/event/RemoteDataChangeEvent.java
new file mode 100644 (file)
index 0000000..9dfd262
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * 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.restconf.broker.event;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.concurrent.ThreadSafe;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.DataChangedNotification;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+@ThreadSafe
+public class RemoteDataChangeEvent implements DataChangeEvent<InstanceIdentifier<? extends DataObject>,DataObject> {
+    private final Map<InstanceIdentifier<?>, DataObject> createdConfig, createdOper, origConfig, origOper, updatedConfig, updatedOper;
+    private final Set<InstanceIdentifier<?>> removedConfig, removedOper;
+
+    public RemoteDataChangeEvent(DataChangedNotification dataChangedNotification) {
+        final Map<InstanceIdentifier<?>, DataObject> createdConfig = new HashMap<>();
+        final Map<InstanceIdentifier<?>, DataObject> createdOper = new HashMap<>();
+        final Map<InstanceIdentifier<?>, DataObject> origConfig = new HashMap<>();
+        final Map<InstanceIdentifier<?>, DataObject> origOper = new HashMap<>();
+        final Map<InstanceIdentifier<?>, DataObject> updatedConfig = new HashMap<>();
+        final Map<InstanceIdentifier<?>, DataObject> updatedOper = new HashMap<>();
+        final Set<InstanceIdentifier<?>> removedConfig = new HashSet<>();
+        final Set<InstanceIdentifier<?>> removedOper = new HashSet<>();
+
+        for (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.data.changed.notification.DataChangeEvent d :dataChangedNotification.getDataChangeEvent()) {
+            switch (d.getOperation()) {
+            case Created:
+                switch (d.getStore()) {
+                case Config:
+                    createdConfig.put(d.getPath(), d);
+                    break;
+                case Operation:
+                    createdOper.put(d.getPath(), d);
+                    break;
+                }
+                break;
+            case Deleted:
+                switch (d.getStore()) {
+                case Config:
+                    removedConfig.add(d.getPath());
+                    break;
+                case Operation:
+                    removedOper.add(d.getPath());
+                    break;
+                }
+                break;
+            case Updated:
+                switch (d.getStore()) {
+                case Config:
+                    origConfig.put(d.getPath(), d);
+                    updatedConfig.put(d.getPath(), d);
+                    break;
+                case Operation:
+                    origOper.put(d.getPath(),d);
+                    updatedOper.put(d.getPath(),d);
+                    break;
+                }
+                break;
+            }
+        }
+
+        this.createdConfig = Collections.unmodifiableMap(createdConfig);
+        this.createdOper = Collections.unmodifiableMap(createdOper);
+        this.origConfig = Collections.unmodifiableMap(origConfig);
+        this.origOper = Collections.unmodifiableMap(origOper);
+        this.updatedConfig = Collections.unmodifiableMap(updatedConfig);
+        this.updatedOper = Collections.unmodifiableMap(updatedOper);
+        this.removedConfig = Collections.unmodifiableSet(removedConfig);
+        this.removedOper = Collections.unmodifiableSet(removedOper);
+    }
+
+    @Override
+    public DataObject getOriginalConfigurationSubtree() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public DataObject getOriginalOperationalSubtree() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public DataObject getUpdatedConfigurationSubtree() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public DataObject getUpdatedOperationalSubtree() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Map<InstanceIdentifier<?>, DataObject> getCreatedOperationalData() {
+        return createdOper;
+    }
+
+    @Override
+    public Map<InstanceIdentifier<?>, DataObject> getCreatedConfigurationData() {
+        return createdConfig;
+    }
+
+    @Override
+    public Map<InstanceIdentifier<?>, DataObject> getUpdatedOperationalData() {
+        return updatedOper;
+    }
+
+    @Override
+    public Map<InstanceIdentifier<?>, DataObject> getUpdatedConfigurationData() {
+        return updatedConfig;
+    }
+
+    @Override
+    public Set<InstanceIdentifier<?>> getRemovedConfigurationData() {
+        return removedConfig;
+    }
+
+    @Override
+    public Set<InstanceIdentifier<?>> getRemovedOperationalData() {
+        return removedOper;
+    }
+
+    @Override
+    public Map<InstanceIdentifier<?>, DataObject> getOriginalConfigurationData() {
+        return origConfig;
+    }
+
+    @Override
+    public Map<InstanceIdentifier<?>, DataObject> getOriginalOperationalData() {
+        return origOper;
+    }
+}
diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/DataBrokerServiceImpl.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/DataBrokerServiceImpl.java
new file mode 100644 (file)
index 0000000..e6659c2
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * 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.restconf.broker.impl;
+
+import com.google.common.base.Optional;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+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;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.BeginTransactionOutput;
+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.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;
+import org.slf4j.LoggerFactory;
+
+public class DataBrokerServiceImpl implements DataBrokerService  {
+
+    private static final Logger logger = LoggerFactory.getLogger(DataBrokerServiceImpl.class.toString());
+    private RestconfClientContext restconfClientContext;
+    private SalRemoteService salRemoteService;
+
+    public DataBrokerServiceImpl(RestconfClientContext restconfClientContext) {
+        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() {
+        Future<RpcResult<BeginTransactionOutput>> rpcResultFuture = this.salRemoteService.beginTransaction();
+        //TODO finish yang model for proper remoteDataModificationTransaction setup
+        RemoteDataModificationTransaction remoteDataModificationTransaction = new RemoteDataModificationTransaction();
+        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 {
+            Optional<DataObject> optDataObject = (Optional<DataObject>) this.restconfClientContext.getConfigurationDatastore().readData(path).get();
+            if (optDataObject.isPresent()){
+                return optDataObject.get();
+            }
+        } catch (InterruptedException e) {
+            logger.trace("Reading configuration data interrupted {}",e);
+        } catch (ExecutionException e) {
+            logger.trace("Reading configuration execution exception {}",e);
+        }
+        throw new IllegalStateException("No data to return.");
+    }
+
+    @Override
+    public DataObject readOperationalData(InstanceIdentifier<? extends DataObject> path) {
+        try {
+            Optional<DataObject> optDataObject = (Optional<DataObject>) this.restconfClientContext.getOperationalDatastore().readData(path).get();
+            if (optDataObject.isPresent()){
+                return optDataObject.get();
+            }
+        } catch (InterruptedException e) {
+            logger.trace("Reading configuration data interrupted {}",e);
+        } catch (ExecutionException e) {
+            logger.trace("Reading configuration execution exception {}",e);
+        }
+        throw new IllegalStateException("No data to return.");
+    }
+    @Override
+    public ListenerRegistration<DataChangeListener> registerDataChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener listener) {
+        CreateDataChangeEventSubscriptionInputBuilder inputBuilder = new CreateDataChangeEventSubscriptionInputBuilder();
+        Future<RpcResult<CreateDataChangeEventSubscriptionOutput>> rpcResultFuture =  salRemoteService.createDataChangeEventSubscription(inputBuilder.setPath(path).build());
+        String streamName = "";
+        try {
+            if (rpcResultFuture.get().isSuccessful()){
+                streamName = rpcResultFuture.get().getResult().getStreamName();
+            }
+        } catch (InterruptedException e) {
+            logger.trace("Interupted while getting rpc result due to {}",e);
+        } catch (ExecutionException e) {
+            logger.trace("Execution exception while getting rpc result due to {}",e);
+        }
+        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 DataChangeListener dataChangeListener;
+        public SalRemoteDataListenerRegistration(DataChangeListener dataChangeListener){
+            this.dataChangeListener = dataChangeListener;
+        }
+        @Override
+        public DataChangeListener getInstance() {
+            return this.dataChangeListener;
+        }
+        @Override
+        public void close() throws Exception {
+            //noop
+        }
+    }
+}
diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/NotificationServiceImpl.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/NotificationServiceImpl.java
new file mode 100644 (file)
index 0000000..3272ce5
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * 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.restconf.broker.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+
+import org.opendaylight.controller.sal.binding.api.NotificationListener;
+import org.opendaylight.controller.sal.binding.api.NotificationService;
+import org.opendaylight.controller.sal.restconf.broker.listeners.RemoteNotificationListener;
+import org.opendaylight.controller.sal.restconf.broker.tools.RemoteStreamTools;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.QName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.SalRemoteService;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext;
+import org.opendaylight.yangtools.restconf.client.api.event.EventStreamInfo;
+import org.opendaylight.yangtools.yang.binding.Notification;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.SetMultimap;
+
+public class NotificationServiceImpl implements NotificationService {
+    private final SalRemoteService salRemoteService;
+    private final RestconfClientContext restconfClientContext;
+
+    private final Multimap<Class<? extends Notification>,NotificationListener<? extends Object>> listeners;
+    private ExecutorService _executor;
+
+    public NotificationServiceImpl(RestconfClientContext restconfClienetContext){
+        this.restconfClientContext = restconfClienetContext;
+        this.salRemoteService = this.restconfClientContext.getRpcServiceContext(SalRemoteService.class).getRpcService();
+
+        HashMultimap<Class<? extends Notification>,NotificationListener<? extends Object>> _create = HashMultimap.<Class<? extends Notification>, NotificationListener<? extends Object>>create();
+        SetMultimap<Class<? extends Notification>,NotificationListener<? extends Object>> _synchronizedSetMultimap = Multimaps.<Class<? extends Notification>, NotificationListener<? extends Object>>synchronizedSetMultimap(_create);
+        this.listeners = _synchronizedSetMultimap;
+
+    }
+    public ExecutorService getExecutor() {
+        return this._executor;
+    }
+
+    public void setExecutor(final ExecutorService executor) {
+        this._executor = executor;
+    }
+
+    @Override
+    public <T extends Notification> void addNotificationListener(Class<T> notificationType, NotificationListener<T> listener) {
+        this.listeners.put(notificationType, listener);
+    }
+
+    @Override
+    public void addNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) {
+        UnsupportedOperationException _unsupportedOperationException = new UnsupportedOperationException("Deprecated method. Use registerNotificationListener instead.");
+        throw _unsupportedOperationException;
+    }
+
+    @Override
+    public void removeNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) {
+        UnsupportedOperationException _unsupportedOperationException = new UnsupportedOperationException(
+                "Deprecated method. Use RegisterNotificationListener returned value to close registration.");
+        throw _unsupportedOperationException;
+    }
+
+    @Override
+    public <T extends Notification> void removeNotificationListener(Class<T> notificationType, NotificationListener<T> listener) {
+        this.listeners.remove(notificationType, listener);
+    }
+
+    @Override
+    public <T extends Notification> Registration<NotificationListener<T>> registerNotificationListener(Class<T> notificationType, NotificationListener<T> listener) {
+        //TODO implementation using sal-remote
+        List<QName> notifications = new ArrayList<QName>();
+        notifications.add(new QName(notificationType.toString()));
+        String notificationStreamName = RemoteStreamTools.createNotificationStream(salRemoteService, notifications);
+        final Map<String,EventStreamInfo> desiredEventStream = RemoteStreamTools.createEventStream(restconfClientContext, notificationStreamName);
+        RemoteNotificationListener remoteNotificationListener = new RemoteNotificationListener(listener);
+        ListenerRegistration<?> listenerRegistration = restconfClientContext.getEventStreamContext(desiredEventStream.get(desiredEventStream.get(notificationStreamName))).registerNotificationListener(remoteNotificationListener);
+        return new SalNotificationRegistration<T>(listenerRegistration);
+    }
+
+    @Override
+    public Registration<org.opendaylight.yangtools.yang.binding.NotificationListener> registerNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) {
+        //TODO implementation using sal-remote
+        String notificationStreamName = RemoteStreamTools.createNotificationStream(salRemoteService, null);
+        final Map<String,EventStreamInfo> desiredEventStream = RemoteStreamTools.createEventStream(restconfClientContext, notificationStreamName);
+        return restconfClientContext.getEventStreamContext(desiredEventStream.get(desiredEventStream.get(notificationStreamName))).registerNotificationListener(listener);
+    }
+
+    private class SalNotificationRegistration<T extends Notification> implements Registration<NotificationListener<T>>{
+        private final Registration<?> registration;
+
+        public SalNotificationRegistration(ListenerRegistration<?> listenerRegistration){
+            this.registration = listenerRegistration;
+        }
+
+        @Override
+        public NotificationListener<T> getInstance() {
+            return this.getInstance();
+        }
+
+        @Override
+        public void close() throws Exception {
+            this.registration.close();
+        }
+    }
+
+
+}
diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/RemoteServicesFactory.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/RemoteServicesFactory.java
new file mode 100644 (file)
index 0000000..65ecd8b
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.broker.impl;
+
+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.yangtools.restconf.client.api.RestconfClientContext;
+
+public class RemoteServicesFactory {
+
+    private final RestconfClientContext restconfClientContext;
+
+    public RemoteServicesFactory(RestconfClientContext restconfClientContext){
+        this.restconfClientContext = restconfClientContext;
+    }
+
+    public DataBrokerService getDataBrokerService(){
+        return new DataBrokerServiceImpl(this.restconfClientContext);
+    }
+
+    public NotificationService getNotificationService(){
+        return  new NotificationServiceImpl(this.restconfClientContext);
+    }
+
+    public RpcConsumerRegistry getRpcConsumerRegistry(){
+        return new RpcConsumerRegistryImpl(this.restconfClientContext);
+    }
+
+}
@@ -5,15 +5,21 @@
  * 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;
+package org.opendaylight.controller.sal.restconf.broker.impl;
 
 import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry;
+import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext;
 import org.opendaylight.yangtools.yang.binding.RpcService;
 
 public class RpcConsumerRegistryImpl implements RpcConsumerRegistry {
+
+    private RestconfClientContext restconfClientContext;
+
+    public RpcConsumerRegistryImpl(RestconfClientContext restconfClientContext){
+        this.restconfClientContext = restconfClientContext;
+    }
     @Override
     public <T extends RpcService> T getRpcService(Class<T> module) {
-        //TODO implementation using restconf-client
-        return null;
+        return restconfClientContext.getRpcServiceContext(module).getRpcService();
     }
 }
diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/RemoteDataChangeNotificationListener.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/RemoteDataChangeNotificationListener.java
new file mode 100644 (file)
index 0000000..df72ac8
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * 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.restconf.broker.listeners;
+
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.restconf.broker.event.RemoteDataChangeEvent;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.DataChangedNotification;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.SalRemoteListener;
+
+public class RemoteDataChangeNotificationListener implements SalRemoteListener {
+
+
+    private final DataChangeListener dataChangeListener;
+
+    public RemoteDataChangeNotificationListener(DataChangeListener dataChangeListener){
+        this.dataChangeListener = dataChangeListener;
+    }
+    @Override
+    public void onDataChangedNotification(DataChangedNotification notification) {
+        this.dataChangeListener.onDataChanged(new RemoteDataChangeEvent(notification));
+    }
+}
diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/RemoteNotificationListener.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/RemoteNotificationListener.java
new file mode 100644 (file)
index 0000000..895a503
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * 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.restconf.broker.listeners;
+
+import org.opendaylight.controller.sal.binding.api.NotificationListener;
+
+public class RemoteNotificationListener implements org.opendaylight.yangtools.yang.binding.NotificationListener {
+
+    org.opendaylight.controller.sal.binding.api.NotificationListener listener;
+
+    public RemoteNotificationListener(NotificationListener listener){
+        this.listener = listener;
+    }
+    public NotificationListener getListener(){
+        return this.listener;
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/SalNotificationListener.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/SalNotificationListener.java
new file mode 100644 (file)
index 0000000..16ca0ae
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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.restconf.broker.listeners;
+
+import org.opendaylight.controller.sal.binding.api.NotificationListener;
+import org.opendaylight.yangtools.yang.binding.Notification;
+
+
+public class SalNotificationListener implements NotificationListener {
+    private NotificationListener notificationListener;
+
+    public SalNotificationListener( NotificationListener notificationListener){
+        this.notificationListener = notificationListener;
+    }
+    @Override
+    public void onNotification(Notification notification) {
+        this.notificationListener.onNotification(notification);
+    }
+}
diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/tools/RemoteStreamTools.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/tools/RemoteStreamTools.java
new file mode 100644 (file)
index 0000000..726f7f0
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * 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.restconf.broker.tools;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateNotificationStreamInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateNotificationStreamOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.QName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.SalRemoteService;
+import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext;
+import org.opendaylight.yangtools.restconf.client.api.event.EventStreamInfo;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RemoteStreamTools {
+    private static final Logger logger = LoggerFactory.getLogger(RemoteStreamTools.class.toString());
+
+    public static String createNotificationStream(SalRemoteService salRemoteService,List<QName> notifications){
+        CreateNotificationStreamInputBuilder notificationStreamInputBuilder = new CreateNotificationStreamInputBuilder();
+
+        if (null == notifications){
+            notificationStreamInputBuilder.setNotifications(notifications);
+        }
+
+        Future<RpcResult<CreateNotificationStreamOutput>> notificationStream = salRemoteService.createNotificationStream(notificationStreamInputBuilder.build());
+
+        String nofiticationStreamIdentifier = "";
+        try {
+            if (notificationStream.get().isSuccessful()){
+                nofiticationStreamIdentifier  = notificationStream.get().getResult().getNotificationStreamIdentifier();
+            }
+        } catch (InterruptedException e) {
+            logger.trace("Interrupted while resolving notification stream identifier due to {}",e);
+        } catch (ExecutionException e) {
+            logger.trace("Execution exception while resolving notification stream identifier due to {}",e);
+        }
+        return nofiticationStreamIdentifier;
+    }
+
+    public static Map<String,EventStreamInfo> createEventStream(RestconfClientContext restconfClientContext, String desiredStreamName){
+        ListenableFuture<Set<EventStreamInfo>> availableEventStreams = restconfClientContext.getAvailableEventStreams();
+        final Map<String,EventStreamInfo> desiredEventStream = new HashMap<String,EventStreamInfo>();
+
+        try {
+            Iterator<EventStreamInfo> it = availableEventStreams.get().iterator();
+            while (it.hasNext()){
+                if (it.next().getIdentifier().equals(desiredStreamName)){
+                    desiredEventStream.put(desiredStreamName,it.next());
+                }
+            }
+        } catch (InterruptedException e) {
+            logger.trace("Resolving of event stream interrupted due to  {}",e);
+        } catch (ExecutionException e) {
+            logger.trace("Resolving of event stream failed due to {}",e);
+        }
+        return desiredEventStream;
+    }
+}
diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/transactions/RemoteDataModificationTransaction.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/transactions/RemoteDataModificationTransaction.java
new file mode 100644 (file)
index 0000000..7f9cc8f
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * 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.restconf.broker.transactions;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Future;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+public class RemoteDataModificationTransaction implements DataModificationTransaction {
+    //TODO implement this
+
+    @Override
+    public Object getIdentifier() {
+        return null;
+    }
+
+    @Override
+    public TransactionStatus getStatus() {
+        return null;
+    }
+
+    @Override
+    public void putRuntimeData(InstanceIdentifier<? extends DataObject> path, DataObject data) {
+
+    }
+
+    @Override
+    public void putOperationalData(InstanceIdentifier<? extends DataObject> path, DataObject data) {
+
+    }
+
+    @Override
+    public void putConfigurationData(InstanceIdentifier<? extends DataObject> path, DataObject data) {
+
+    }
+
+    @Override
+    public void removeRuntimeData(InstanceIdentifier<? extends DataObject> path) {
+
+    }
+
+    @Override
+    public void removeOperationalData(InstanceIdentifier<? extends DataObject> path) {
+
+    }
+
+    @Override
+    public void removeConfigurationData(InstanceIdentifier<? extends DataObject> path) {
+
+    }
+
+    @Override
+    public Future<RpcResult<TransactionStatus>> commit() {
+        return null;
+    }
+
+    @Override
+    public ListenerRegistration<DataTransactionListener> registerListener(DataTransactionListener listener) {
+        return null;
+    }
+
+    @Override
+    public Map<InstanceIdentifier<? extends DataObject>, DataObject> getCreatedOperationalData() {
+        return null;
+    }
+
+    @Override
+    public Map<InstanceIdentifier<? extends DataObject>, DataObject> getCreatedConfigurationData() {
+        return null;
+    }
+
+    @Override
+    public Map<InstanceIdentifier<? extends DataObject>, DataObject> getUpdatedOperationalData() {
+        return null;
+    }
+
+    @Override
+    public Map<InstanceIdentifier<? extends DataObject>, DataObject> getUpdatedConfigurationData() {
+        return null;
+    }
+
+    @Override
+    public Set<InstanceIdentifier<? extends DataObject>> getRemovedConfigurationData() {
+        return null;
+    }
+
+    @Override
+    public Set<InstanceIdentifier<? extends DataObject>> getRemovedOperationalData() {
+        return null;
+    }
+
+    @Override
+    public Map<InstanceIdentifier<? extends DataObject>, DataObject> getOriginalConfigurationData() {
+        return null;
+    }
+
+    @Override
+    public Map<InstanceIdentifier<? extends DataObject>, DataObject> getOriginalOperationalData() {
+        return null;
+    }
+
+    @Override
+    public DataObject readOperationalData(InstanceIdentifier<? extends DataObject> path) {
+        return null;
+    }
+
+    @Override
+    public DataObject readConfigurationData(InstanceIdentifier<? extends DataObject> path) {
+        return null;
+    }
+}
diff --git a/opendaylight/md-sal/sal-restconf-broker/src/test/java/org/opendaylight/controller/sal/binding/impl/test/DataBrokerImplTest.java b/opendaylight/md-sal/sal-restconf-broker/src/test/java/org/opendaylight/controller/sal/binding/impl/test/DataBrokerImplTest.java
new file mode 100644 (file)
index 0000000..eafc47d
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * 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.binding.impl.test;
+
+public class DataBrokerImplTest {
+
+    public static void main(String[] args){
+
+    }
+}
diff --git a/opendaylight/md-sal/sal-restconf-broker/src/test/java/org/opendaylight/controller/sal/binding/impl/test/NotificationServiceImplTest.java b/opendaylight/md-sal/sal-restconf-broker/src/test/java/org/opendaylight/controller/sal/binding/impl/test/NotificationServiceImplTest.java
new file mode 100644 (file)
index 0000000..a91b06e
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * 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.binding.impl.test;
+
+public class NotificationServiceImplTest {
+
+    public static void main(String[] args){
+
+    }
+}
index fde60d64ceb148b01daa037c4d037c7182dafd41..87e5787ef5c9f63df75c95344ae4ac64e608b76a 100644 (file)
@@ -11,18 +11,14 @@ 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.sal.binding.api.NotificationListener;
 import org.opendaylight.controller.sal.binding.api.NotificationService;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
-import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
-import org.opendaylight.controller.sal.common.GlobalDataStore;
 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.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;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.osgi.framework.BundleActivator;
@@ -71,7 +67,7 @@ public class ToastConsumerImpl extends AbstractBindingAwareConsumer implements B
     public void onSessionInitialized(ConsumerContext session) {
         this.session = session;
         NotificationService notificationService = session.getSALService(NotificationService.class);
-        notificationService.addNotificationListener(ToastDone.class, this);
+        notificationService.registerNotificationListener(ToastDone.class, this);
     }
 
     @Override
index 5ba67474b36c3027a6c0ffb6fbc6322c4846d056..ae482ed9786f38d0d0f2e81af458922c92d8a824 100644 (file)
@@ -11,16 +11,10 @@ import java.util.Collection;
 import java.util.Collections;
 
 import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
-import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
-import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
 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.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -28,7 +22,7 @@ public class ToasterProvider extends AbstractBindingAwareProvider {
     private static final Logger log = LoggerFactory.getLogger(ToasterProvider.class);
 
     private ProviderContext providerContext;
-    private OpendaylightToaster toaster;
+    private final OpendaylightToaster toaster;
 
     public ToasterProvider() {
         toaster = new OpendaylightToaster();
index 0f90ecac60e1f57307da4ee810cecbeb2a1a75d6..5c3fc2329af03cf5b44f079ec211a2cdff06ca26 100644 (file)
             <groupId>org.eclipse.xtend</groupId>
             <artifactId>org.eclipse.xtend.lib</artifactId>
         </dependency>
+        
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-log4j12</artifactId>
+            <version>${slf4j.version}</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractListeningStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractListeningStatsTracker.java
new file mode 100644 (file)
index 0000000..4a58579
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+abstract class AbstractListeningStatsTracker<I, K> extends AbstractStatsTracker<I, K> implements AutoCloseable, DataChangeListener {
+    private static final Logger logger = LoggerFactory.getLogger(AbstractListeningStatsTracker.class);
+    private ListenerRegistration<?> reg;
+
+    protected AbstractListeningStatsTracker(FlowCapableContext context, long lifetimeNanos) {
+        super(context, lifetimeNanos);
+    }
+
+    protected abstract InstanceIdentifier<?> listenPath();
+    protected abstract String statName();
+
+    public void start(final DataBrokerService dbs) {
+        Preconditions.checkState(reg == null);
+
+        reg = dbs.registerDataChangeListener(listenPath(), this);
+        logger.debug("{} Statistics tracker for node {} started", statName(), getNodeIdentifier());
+    }
+
+    @Override
+    public final void close() {
+        if (reg != null) {
+            try {
+                reg.close();
+            } catch (Exception e) {
+                logger.warn("Failed to stop {} Statistics tracker for node {}", statName(), getNodeIdentifier(), e);
+            }
+            reg = null;
+        }
+    }
+}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractStatsTracker.java
new file mode 100644 (file)
index 0000000..c29b6a7
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright IBM Corporation, 2013.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionAware;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.JdkFutureAdapters;
+
+abstract class AbstractStatsTracker<I, K> {
+    private static final Logger logger = LoggerFactory.getLogger(AbstractStatsTracker.class);
+    private final FutureCallback<RpcResult<? extends TransactionAware>> callback =
+            new FutureCallback<RpcResult<? extends TransactionAware>>() {
+        @Override
+        public void onSuccess(RpcResult<? extends TransactionAware> result) {
+            if (result.isSuccessful()) {
+                final TransactionId id = result.getResult().getTransactionId();
+                if (id == null) {
+                    final Throwable t = new UnsupportedOperationException("No protocol support");
+                    t.fillInStackTrace();
+                    onFailure(t);
+                } else {
+                    context.registerTransaction(id);
+                }
+            } else {
+                logger.debug("Statistics request failed: {}", result.getErrors());
+
+                final Throwable t = new RPCFailedException("Failed to send statistics request", result.getErrors());
+                t.fillInStackTrace();
+                onFailure(t);
+            }
+        }
+
+        @Override
+        public void onFailure(Throwable t) {
+            logger.debug("Failed to send statistics request", t);
+        }
+    };
+
+    private final Map<K, Long> trackedItems = new HashMap<>();
+    private final FlowCapableContext context;
+    private final long lifetimeNanos;
+
+    protected AbstractStatsTracker(final FlowCapableContext context, final long lifetimeNanos) {
+        this.context = Preconditions.checkNotNull(context);
+        this.lifetimeNanos = lifetimeNanos;
+    }
+
+    protected final InstanceIdentifierBuilder<Node> getNodeIdentifierBuilder() {
+        return InstanceIdentifier.builder(getNodeIdentifier());
+    }
+
+    protected final NodeRef getNodeRef() {
+        return context.getNodeRef();
+    }
+
+    protected final InstanceIdentifier<Node> getNodeIdentifier() {
+        return context.getNodeIdentifier();
+    }
+
+    protected final <T extends TransactionAware> void requestHelper(Future<RpcResult<T>> future) {
+        Futures.addCallback(JdkFutureAdapters.listenInPoolThread(future), callback);
+    }
+
+    protected final DataModificationTransaction startTransaction() {
+        return context.startDataModification();
+    }
+
+    protected abstract void cleanupSingleStat(DataModificationTransaction trans, K item);
+    protected abstract K updateSingleStat(DataModificationTransaction trans, I item);
+
+    public final synchronized void updateStats(List<I> list) {
+        final Long expiryTime = System.nanoTime() + lifetimeNanos;
+        final DataModificationTransaction trans = startTransaction();
+
+        for (final I item : list) {
+            trackedItems.put(updateSingleStat(trans, item), expiryTime);
+        }
+
+        trans.commit();
+    }
+
+    public final synchronized void cleanup(final DataModificationTransaction trans, long now) {
+        for (Iterator<Entry<K, Long>> it = trackedItems.entrySet().iterator();it.hasNext();){
+            Entry<K, Long> e = it.next();
+            if (now > e.getValue()) {
+                cleanupSingleStat(trans, e.getKey());
+                it.remove();
+            }
+        }
+    }
+}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowCapableContext.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowCapableContext.java
new file mode 100644 (file)
index 0000000..520b344
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Interface exposed to AbstractStatsTracker by its parent NodeStatisticsHandler.
+ * While we could simply exist without this interface, its purpose is to document
+ * the contract between the two classes.
+ */
+interface FlowCapableContext {
+    InstanceIdentifier<Node> getNodeIdentifier();
+    NodeRef getNodeRef();
+    DataModificationTransaction startDataModification();
+    void registerTransaction(TransactionId id);
+    void registerTableTransaction(TransactionId id, Short tableId);
+}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowCapableTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowCapableTracker.java
new file mode 100644 (file)
index 0000000..bb1544c
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright IBM Corporation, 2013.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import java.util.Collection;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Sets;
+
+/**
+ * There is a single instance of this class and that instance is responsible for
+ * monitoring the operational data store for nodes being created/deleted and
+ * notifying StatisticsProvider. These events then control the lifecycle of
+ * NodeStatisticsHandler for a particular switch.
+ */
+final class FlowCapableTracker implements DataChangeListener {
+    private static final Logger logger = LoggerFactory.getLogger(FlowCapableTracker.class);
+
+    private final InstanceIdentifier<FlowCapableNode> root;
+    private final StatisticsProvider stats;
+
+    private final Predicate<InstanceIdentifier<?>> filterIdentifiers = new Predicate<InstanceIdentifier<?>>() {
+        @Override
+        public boolean apply(final InstanceIdentifier<?> input) {
+            /*
+             * This notification has been triggered either by the ancestor,
+             * descendant or directly for the FlowCapableNode itself. We
+             * are not interested descendants, so let's prune them based
+             * on the depth of their identifier.
+             */
+            if (root.getPath().size() < input.getPath().size()) {
+                logger.debug("Ignoring notification for descendant {}", input);
+                return false;
+            }
+
+            logger.debug("Including notification for {}", input);
+            return true;
+        }
+    };
+
+    public FlowCapableTracker(final StatisticsProvider stats, InstanceIdentifier<FlowCapableNode> root) {
+        this.stats = Preconditions.checkNotNull(stats);
+        this.root = Preconditions.checkNotNull(root);
+    }
+
+    /*
+     * This method is synchronized because we want to make sure to serialize input
+     * from the datastore. Competing add/remove could be problematic otherwise.
+     */
+    @Override
+    public synchronized void onDataChanged(final DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+        logger.debug("Tracker at root {} processing notification", root);
+
+        /*
+         * First process all the identifiers which were removed, trying to figure out
+         * whether they constitute removal of FlowCapableNode.
+         */
+        final Collection<NodeKey> removedNodes =
+            Collections2.filter(Collections2.transform(
+                Sets.filter(change.getRemovedOperationalData(), filterIdentifiers),
+                new Function<InstanceIdentifier<?>, NodeKey>() {
+                    @Override
+                    public NodeKey apply(final InstanceIdentifier<?> input) {
+                        final NodeKey key = input.firstKeyOf(Node.class, NodeKey.class);
+                        if (key == null) {
+                            // FIXME: do we have a backup plan?
+                            logger.info("Failed to extract node key from {}", input);
+                        }
+                        return key;
+                    }
+                }), Predicates.notNull());
+        stats.stopNodeHandlers(removedNodes);
+
+        final Collection<NodeKey> addedNodes =
+            Collections2.filter(Collections2.transform(
+                Sets.filter(change.getCreatedOperationalData().keySet(), filterIdentifiers),
+                new Function<InstanceIdentifier<?>, NodeKey>() {
+                    @Override
+                    public NodeKey apply(final InstanceIdentifier<?> input) {
+                        final NodeKey key = input.firstKeyOf(Node.class, NodeKey.class);
+                        if (key == null) {
+                            // FIXME: do we have a backup plan?
+                            logger.info("Failed to extract node key from {}", input);
+                    }
+                    return key;
+                }
+            }), Predicates.notNull());
+        stats.startNodeHandlers(addedNodes);
+
+        logger.debug("Tracker at root {} finished processing notification", root);
+    }
+}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowComparator.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowComparator.java
new file mode 100644 (file)
index 0000000..af61db1
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ * Copyright IBM Corporation, 2013.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.annotations.VisibleForTesting;
+
+/**
+ * Utility class for comparing flows.
+ */
+final class FlowComparator {
+    private final static Logger logger = LoggerFactory.getLogger(FlowComparator.class);
+
+    private FlowComparator() {
+
+    }
+
+    public static boolean flowEquals(Flow statsFlow, Flow storedFlow) {
+        if (statsFlow.getClass() != storedFlow.getClass()) {
+            return false;
+        }
+        if (statsFlow.getContainerName()== null) {
+            if (storedFlow.getContainerName()!= null) {
+                return false;
+            }
+        } else if(!statsFlow.getContainerName().equals(storedFlow.getContainerName())) {
+            return false;
+        }
+        if (statsFlow.getMatch()== null) {
+            if (storedFlow.getMatch() != null) {
+                return false;
+            }
+        } //else if(!statsFlow.getMatch().equals(storedFlow.getMatch())) {
+        else if(!matchEquals(statsFlow.getMatch(), storedFlow.getMatch())) {
+            return false;
+        }
+        if (storedFlow.getPriority() == null) {
+            if (statsFlow.getPriority() != null && statsFlow.getPriority()!= 0x8000) {
+                return false;
+            }
+        } else if(!statsFlow.getPriority().equals(storedFlow.getPriority())) {
+            return false;
+        }
+        if (statsFlow.getTableId() == null) {
+            if (storedFlow.getTableId() != null) {
+                return false;
+            }
+        } else if(!statsFlow.getTableId().equals(storedFlow.getTableId())) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Explicit equals method to compare the 'match' for flows stored in the data-stores and flow fetched from the switch.
+     * Flow installation process has three steps
+     * 1) Store flow in config data store
+     * 2) and send it to plugin for installation
+     * 3) Flow gets installed in switch
+     *
+     * The flow user wants to install and what finally gets installed in switch can be slightly different.
+     * E.g, If user installs flow with src/dst ip=10.0.0.1/24, when it get installed in the switch
+     * src/dst ip will be changes to 10.0.0.0/24 because of netmask of 24. When statistics manager fetch
+     * stats it gets 10.0.0.0/24 rather then 10.0.0.1/24. Custom match takes care of by using masked ip
+     * while comparing two ip addresses.
+     *
+     * Sometimes when user don't provide few values that is required by flow installation request, like
+     * priority,hard timeout, idle timeout, cookies etc, plugin usages default values before sending
+     * request to the switch. So when statistics manager gets flow statistics, it gets the default value.
+     * But the flow stored in config data store don't have those defaults value. I included those checks
+     * in the customer flow/match equal function.
+     *
+     *
+     * @param statsFlow
+     * @param storedFlow
+     * @return
+     */
+    public static boolean matchEquals(Match statsFlow, Match storedFlow) {
+        if (statsFlow == storedFlow) {
+            return true;
+        }
+        if (storedFlow.getClass() != statsFlow.getClass()) {
+            return false;
+        }
+        if (storedFlow.getEthernetMatch() == null) {
+            if (statsFlow.getEthernetMatch() != null) {
+                return false;
+            }
+        } else if(!storedFlow.getEthernetMatch().equals(statsFlow.getEthernetMatch())) {
+            return false;
+        }
+        if (storedFlow.getIcmpv4Match()== null) {
+            if (statsFlow.getIcmpv4Match() != null) {
+                return false;
+            }
+        } else if(!storedFlow.getIcmpv4Match().equals(statsFlow.getIcmpv4Match())) {
+            return false;
+        }
+        if (storedFlow.getIcmpv6Match() == null) {
+            if (statsFlow.getIcmpv6Match() != null) {
+                return false;
+            }
+        } else if(!storedFlow.getIcmpv6Match().equals(statsFlow.getIcmpv6Match())) {
+            return false;
+        }
+        if (storedFlow.getInPhyPort() == null) {
+            if (statsFlow.getInPhyPort() != null) {
+                return false;
+            }
+        } else if(!storedFlow.getInPhyPort().equals(statsFlow.getInPhyPort())) {
+            return false;
+        }
+        if (storedFlow.getInPort()== null) {
+            if (statsFlow.getInPort() != null) {
+                return false;
+            }
+        } else if(!storedFlow.getInPort().equals(statsFlow.getInPort())) {
+            return false;
+        }
+        if (storedFlow.getIpMatch()== null) {
+            if (statsFlow.getIpMatch() != null) {
+                return false;
+            }
+        } else if(!storedFlow.getIpMatch().equals(statsFlow.getIpMatch())) {
+            return false;
+        }
+        if (storedFlow.getLayer3Match()== null) {
+            if (statsFlow.getLayer3Match() != null) {
+                    return false;
+            }
+        } else if(!layer3MatchEquals(statsFlow.getLayer3Match(),storedFlow.getLayer3Match())) {
+            return false;
+        }
+        if (storedFlow.getLayer4Match()== null) {
+            if (statsFlow.getLayer4Match() != null) {
+                return false;
+            }
+        } else if(!storedFlow.getLayer4Match().equals(statsFlow.getLayer4Match())) {
+            return false;
+        }
+        if (storedFlow.getMetadata() == null) {
+            if (statsFlow.getMetadata() != null) {
+                return false;
+            }
+        } else if(!storedFlow.getMetadata().equals(statsFlow.getMetadata())) {
+            return false;
+        }
+        if (storedFlow.getProtocolMatchFields() == null) {
+            if (statsFlow.getProtocolMatchFields() != null) {
+                return false;
+            }
+        } else if(!storedFlow.getProtocolMatchFields().equals(statsFlow.getProtocolMatchFields())) {
+            return false;
+        }
+        if (storedFlow.getTunnel()== null) {
+            if (statsFlow.getTunnel() != null) {
+                return false;
+            }
+        } else if(!storedFlow.getTunnel().equals(statsFlow.getTunnel())) {
+            return false;
+        }
+        if (storedFlow.getVlanMatch()== null) {
+            if (statsFlow.getVlanMatch() != null) {
+                return false;
+            }
+        } else if(!storedFlow.getVlanMatch().equals(statsFlow.getVlanMatch())) {
+            return false;
+        }
+        return true;
+    }
+
+    @VisibleForTesting
+    static boolean layer3MatchEquals(Layer3Match statsLayer3Match, Layer3Match storedLayer3Match){
+        boolean verdict = true;
+        if(statsLayer3Match instanceof Ipv4Match && storedLayer3Match instanceof Ipv4Match){
+            Ipv4Match statsIpv4Match = (Ipv4Match)statsLayer3Match;
+            Ipv4Match storedIpv4Match = (Ipv4Match)storedLayer3Match;
+
+            if (verdict) {
+                verdict = compareNullSafe(
+                        storedIpv4Match.getIpv4Destination(), statsIpv4Match.getIpv4Destination());
+            }
+            if (verdict) {
+                verdict = compareNullSafe(
+                        statsIpv4Match.getIpv4Source(), storedIpv4Match.getIpv4Source());
+            }
+        } else {
+            Boolean nullCheckOut = checkNullValues(storedLayer3Match, statsLayer3Match);
+            if (nullCheckOut != null) {
+                verdict = nullCheckOut;
+            } else {
+                verdict = storedLayer3Match.equals(statsLayer3Match);
+            }
+        }
+
+        return verdict;
+    }
+
+    private static boolean compareNullSafe(Ipv4Prefix statsIpv4, Ipv4Prefix storedIpv4) {
+        boolean verdict = true;
+        Boolean checkDestNullValuesOut = checkNullValues(storedIpv4, statsIpv4);
+        if (checkDestNullValuesOut != null) {
+            verdict = checkDestNullValuesOut;
+        } else if(!IpAddressEquals(statsIpv4, storedIpv4)){
+            verdict = false;
+        }
+
+        return verdict;
+    }
+
+    private static Boolean checkNullValues(Object v1, Object v2) {
+        Boolean verdict = null;
+        if (v1 == null && v2 != null) {
+            verdict = Boolean.FALSE;
+        } else if (v1 != null && v2 == null) {
+            verdict = Boolean.FALSE;
+        } else if (v1 == null && v2 == null) {
+            verdict = Boolean.TRUE;
+        }
+
+        return verdict;
+    }
+
+    /**
+     * TODO: why don't we use the default Ipv4Prefix.equals()?
+     *
+     * @param statsIpAddress
+     * @param storedIpAddress
+     * @return true if IPv4prefixes equals
+     */
+    private static boolean IpAddressEquals(Ipv4Prefix statsIpAddress, Ipv4Prefix storedIpAddress) {
+        IntegerIpAddress statsIpAddressInt = StrIpToIntIp(statsIpAddress.getValue());
+        IntegerIpAddress storedIpAddressInt = StrIpToIntIp(storedIpAddress.getValue());
+
+        if(IpAndMaskBasedMatch(statsIpAddressInt,storedIpAddressInt)){
+            return true;
+        }
+        if(IpBasedMatch(statsIpAddressInt,storedIpAddressInt)){
+            return true;
+        }
+        return false;
+    }
+
+    private static boolean IpAndMaskBasedMatch(IntegerIpAddress statsIpAddressInt,IntegerIpAddress storedIpAddressInt){
+        return ((statsIpAddressInt.getIp() & statsIpAddressInt.getMask()) ==  (storedIpAddressInt.getIp() & storedIpAddressInt.getMask()));
+    }
+
+    private static boolean IpBasedMatch(IntegerIpAddress statsIpAddressInt,IntegerIpAddress storedIpAddressInt){
+        return (statsIpAddressInt.getIp() == storedIpAddressInt.getIp());
+    }
+
+    /**
+     * Method return integer version of ip address. Converted int will be mask if
+     * mask specified
+     */
+    private static IntegerIpAddress StrIpToIntIp(String ipAddresss){
+
+        String[] parts = ipAddresss.split("/");
+        String ip = parts[0];
+        int prefix;
+
+        if (parts.length < 2) {
+            prefix = 32;
+        } else {
+            prefix = Integer.parseInt(parts[1]);
+        }
+
+        IntegerIpAddress integerIpAddress = null;
+        try {
+            Inet4Address addr = (Inet4Address) InetAddress.getByName(ip);
+            byte[] addrBytes = addr.getAddress();
+            int ipInt = ((addrBytes[0] & 0xFF) << 24) |
+                    ((addrBytes[1] & 0xFF) << 16) |
+                    ((addrBytes[2] & 0xFF) << 8)  |
+                    ((addrBytes[3] & 0xFF) << 0);
+
+            int mask = 0xffffffff << 32 - prefix;
+
+            integerIpAddress = new IntegerIpAddress(ipInt, mask);
+        } catch (UnknownHostException e){
+            logger.error("Failed to determine host IP address by name: {}", e.getMessage(), e);
+        }
+
+        return integerIpAddress;
+    }
+
+    private static class IntegerIpAddress{
+        int ip;
+        int mask;
+        public IntegerIpAddress(int ip, int mask) {
+            this.ip = ip;
+            this.mask = mask;
+        }
+        public int getIp() {
+            return ip;
+        }
+        public int getMask() {
+            return mask;
+        }
+    }
+}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsEntry.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsEntry.java
new file mode 100644 (file)
index 0000000..b5b39d9
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright IBM Corporation, 2013.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+
+final class FlowStatsEntry {
+    private final Short tableId;
+    private final Flow flow;
+
+    public FlowStatsEntry(Short tableId, Flow flow){
+        this.tableId = tableId;
+        this.flow = flow;
+    }
+
+    public Short getTableId() {
+        return tableId;
+    }
+
+    public Flow getFlow() {
+        return flow;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((flow == null) ? 0 : flow.hashCode());
+        result = prime * result + ((tableId == null) ? 0 : tableId.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        FlowStatsEntry other = (FlowStatsEntry) obj;
+        if (flow == null) {
+            if (other.flow != null)
+                return false;
+        } else if (!flow.equals(other.flow))
+            return false;
+        if (tableId == null) {
+            if (other.tableId != null)
+                return false;
+        } else if (!tableId.equals(other.tableId))
+            return false;
+        return true;
+    }
+}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java
new file mode 100644 (file)
index 0000000..90ddc28
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * Copyright IBM Corporation, 2013.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsFromFlowTableInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.statistics.FlowStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class FlowStatsTracker extends AbstractListeningStatsTracker<FlowAndStatisticsMapList, FlowStatsEntry> {
+    private static final Logger logger = LoggerFactory.getLogger(FlowStatsTracker.class);
+    private final OpendaylightFlowStatisticsService flowStatsService;
+    private int unaccountedFlowsCounter = 1;
+
+    FlowStatsTracker(OpendaylightFlowStatisticsService flowStatsService, final FlowCapableContext context, long lifetimeNanos) {
+        super(context, lifetimeNanos);
+        this.flowStatsService = flowStatsService;
+    }
+
+    @Override
+    protected void cleanupSingleStat(DataModificationTransaction trans, FlowStatsEntry item) {
+        InstanceIdentifier<?> flowRef = getNodeIdentifierBuilder()
+                            .augmentation(FlowCapableNode.class)
+                            .child(Table.class, new TableKey(item.getTableId()))
+                            .child(Flow.class,item.getFlow().getKey())
+                            .augmentation(FlowStatisticsData.class).toInstance();
+        trans.removeOperationalData(flowRef);
+    }
+
+    @Override
+    protected FlowStatsEntry updateSingleStat(DataModificationTransaction trans, FlowAndStatisticsMapList map) {
+        short tableId = map.getTableId();
+
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        FlowStatisticsDataBuilder flowStatisticsData = new FlowStatisticsDataBuilder();
+
+        FlowBuilder flow = new FlowBuilder();
+        flow.setContainerName(map.getContainerName());
+        flow.setBufferId(map.getBufferId());
+        flow.setCookie(map.getCookie());
+        flow.setCookieMask(map.getCookieMask());
+        flow.setFlags(map.getFlags());
+        flow.setFlowName(map.getFlowName());
+        flow.setHardTimeout(map.getHardTimeout());
+        if(map.getFlowId() != null)
+            flow.setId(new FlowId(map.getFlowId().getValue()));
+        flow.setIdleTimeout(map.getIdleTimeout());
+        flow.setInstallHw(map.isInstallHw());
+        flow.setInstructions(map.getInstructions());
+        if(map.getFlowId()!= null)
+            flow.setKey(new FlowKey(new FlowId(map.getKey().getFlowId().getValue())));
+        flow.setMatch(map.getMatch());
+        flow.setOutGroup(map.getOutGroup());
+        flow.setOutPort(map.getOutPort());
+        flow.setPriority(map.getPriority());
+        flow.setStrict(map.isStrict());
+        flow.setTableId(tableId);
+
+        Flow flowRule = flow.build();
+
+        FlowAndStatisticsMapListBuilder stats = new FlowAndStatisticsMapListBuilder();
+        stats.setByteCount(map.getByteCount());
+        stats.setPacketCount(map.getPacketCount());
+        stats.setDuration(map.getDuration());
+
+        GenericStatistics flowStats = stats.build();
+
+        //Augment the data to the flow node
+
+        FlowStatisticsBuilder flowStatistics = new FlowStatisticsBuilder();
+        flowStatistics.setByteCount(flowStats.getByteCount());
+        flowStatistics.setPacketCount(flowStats.getPacketCount());
+        flowStatistics.setDuration(flowStats.getDuration());
+        flowStatistics.setContainerName(map.getContainerName());
+        flowStatistics.setBufferId(map.getBufferId());
+        flowStatistics.setCookie(map.getCookie());
+        flowStatistics.setCookieMask(map.getCookieMask());
+        flowStatistics.setFlags(map.getFlags());
+        flowStatistics.setFlowName(map.getFlowName());
+        flowStatistics.setHardTimeout(map.getHardTimeout());
+        flowStatistics.setIdleTimeout(map.getIdleTimeout());
+        flowStatistics.setInstallHw(map.isInstallHw());
+        flowStatistics.setInstructions(map.getInstructions());
+        flowStatistics.setMatch(map.getMatch());
+        flowStatistics.setOutGroup(map.getOutGroup());
+        flowStatistics.setOutPort(map.getOutPort());
+        flowStatistics.setPriority(map.getPriority());
+        flowStatistics.setStrict(map.isStrict());
+        flowStatistics.setTableId(tableId);
+
+        flowStatisticsData.setFlowStatistics(flowStatistics.build());
+
+        logger.debug("Flow : {}",flowRule.toString());
+        logger.debug("Statistics to augment : {}",flowStatistics.build().toString());
+
+        InstanceIdentifier<Table> tableRef = getNodeIdentifierBuilder()
+                .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
+
+        //TODO: Not a good way to do it, need to figure out better way.
+        //TODO: major issue in any alternate approach is that flow key is incrementally assigned
+        //to the flows stored in data store.
+        // Augment same statistics to all the matching masked flow
+        Table table= (Table)trans.readConfigurationData(tableRef);
+        if(table != null){
+            for(Flow existingFlow : table.getFlow()){
+                logger.debug("Existing flow in data store : {}",existingFlow.toString());
+                if(FlowComparator.flowEquals(flowRule,existingFlow)){
+                    InstanceIdentifier<Flow> flowRef = getNodeIdentifierBuilder()
+                            .augmentation(FlowCapableNode.class)
+                            .child(Table.class, new TableKey(tableId))
+                            .child(Flow.class,existingFlow.getKey()).toInstance();
+                    flowBuilder.setKey(existingFlow.getKey());
+                    flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
+                    logger.debug("Found matching flow in the datastore, augmenting statistics");
+                    // Update entry with timestamp of latest response
+                    flow.setKey(existingFlow.getKey());
+                    FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId,flow.build());
+                    trans.putOperationalData(flowRef, flowBuilder.build());
+                    return flowStatsEntry;
+                }
+            }
+        }
+
+        table = (Table)trans.readOperationalData(tableRef);
+        if(table != null){
+            for(Flow existingFlow : table.getFlow()){
+                FlowStatisticsData augmentedflowStatisticsData = existingFlow.getAugmentation(FlowStatisticsData.class);
+                if(augmentedflowStatisticsData != null){
+                    FlowBuilder existingOperationalFlow = new FlowBuilder();
+                    existingOperationalFlow.fieldsFrom(augmentedflowStatisticsData.getFlowStatistics());
+                    logger.debug("Existing unaccounted flow in operational data store : {}",existingFlow.toString());
+                    if(FlowComparator.flowEquals(flowRule,existingOperationalFlow.build())){
+                        InstanceIdentifier<Flow> flowRef = getNodeIdentifierBuilder()
+                                .augmentation(FlowCapableNode.class)
+                                .child(Table.class, new TableKey(tableId))
+                                .child(Flow.class,existingFlow.getKey()).toInstance();
+                        flowBuilder.setKey(existingFlow.getKey());
+                        flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
+                        logger.debug("Found matching unaccounted flow in the operational datastore, augmenting statistics");
+                        // Update entry with timestamp of latest response
+                        flow.setKey(existingFlow.getKey());
+                        FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId,flow.build());
+                        trans.putOperationalData(flowRef, flowBuilder.build());
+                        return flowStatsEntry;
+                    }
+                }
+            }
+        }
+
+        String flowKey = "#UF$TABLE*"+Short.toString(tableId)+"*"+Integer.toString(this.unaccountedFlowsCounter);
+        this.unaccountedFlowsCounter++;
+        FlowKey newFlowKey = new FlowKey(new FlowId(flowKey));
+        InstanceIdentifier<Flow> flowRef = getNodeIdentifierBuilder().augmentation(FlowCapableNode.class)
+                    .child(Table.class, new TableKey(tableId))
+                    .child(Flow.class,newFlowKey).toInstance();
+        flowBuilder.setKey(newFlowKey);
+        flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
+        logger.debug("Flow {} is not present in config data store, augmenting statistics as an unaccounted flow",
+                    flowBuilder.build());
+
+        // Update entry with timestamp of latest response
+        flow.setKey(newFlowKey);
+        FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId,flow.build());
+        trans.putOperationalData(flowRef, flowBuilder.build());
+        return flowStatsEntry;
+    }
+
+    @Override
+    protected InstanceIdentifier<?> listenPath() {
+        return getNodeIdentifierBuilder().augmentation(FlowCapableNode.class).child(Table.class).child(Flow.class).build();
+    }
+
+    @Override
+    protected String statName() {
+        return "Flow";
+    }
+
+    public void requestAllFlowsAllTables() {
+        if (flowStatsService != null) {
+            final GetAllFlowsStatisticsFromAllFlowTablesInputBuilder input = new GetAllFlowsStatisticsFromAllFlowTablesInputBuilder();
+            input.setNode(getNodeRef());
+
+            requestHelper(flowStatsService.getAllFlowsStatisticsFromAllFlowTables(input.build()));
+        }
+    }
+
+    public void requestAggregateFlows(final TableKey key) {
+        if (flowStatsService != null) {
+            GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder input =
+                    new GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder();
+
+            input.setNode(getNodeRef());
+            input.setTableId(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId(key.getId()));
+            requestHelper(flowStatsService.getAggregateFlowStatisticsFromFlowTableForAllFlows(input.build()));
+        }
+    }
+
+    public void requestFlow(final Flow flow) {
+        if (flowStatsService != null) {
+            final GetFlowStatisticsFromFlowTableInputBuilder input =
+                    new GetFlowStatisticsFromFlowTableInputBuilder(flow);
+            input.setNode(getNodeRef());
+
+            requestHelper(flowStatsService.getFlowStatisticsFromFlowTable(input.build()));
+        }
+    }
+
+    @Override
+    public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+        for (Entry<InstanceIdentifier<?>, DataObject> e : change.getCreatedConfigurationData().entrySet()) {
+            if (Flow.class.equals(e.getKey().getTargetType())) {
+                final Flow flow = (Flow) e.getValue();
+                logger.debug("Key {} triggered request for flow {}", e.getKey(), flow);
+                requestFlow(flow);
+            } else {
+                logger.debug("Ignoring key {}", e.getKey());
+            }
+        }
+
+        final DataModificationTransaction trans = startTransaction();
+        for (InstanceIdentifier<?> key : change.getRemovedConfigurationData()) {
+            if (Flow.class.equals(key.getTargetType())) {
+                @SuppressWarnings("unchecked")
+                final InstanceIdentifier<Flow> flow = (InstanceIdentifier<Flow>)key;
+                final InstanceIdentifier<?> del = InstanceIdentifier.builder(flow)
+                        .augmentation(FlowStatisticsData.class).build();
+                logger.debug("Key {} triggered remove of augmentation {}", key, del);
+
+                trans.removeOperationalData(del);
+            }
+        }
+        trans.commit();
+    }
+
+    @Override
+    public void start(final DataBrokerService dbs) {
+        if (flowStatsService == null) {
+            logger.debug("No Flow Statistics service, not subscribing to flows on node {}", getNodeIdentifier());
+            return;
+        }
+
+        super.start(dbs);
+    }
+}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowTableStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowTableStatsTracker.java
new file mode 100644 (file)
index 0000000..3fe68c1
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright IBM Corporation, 2013.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import java.util.Collections;
+import java.util.Set;
+import java.util.concurrent.ConcurrentSkipListSet;
+
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+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.table.statistics.rev131215.FlowTableStatisticsData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatistics;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatisticsBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+final class FlowTableStatsTracker extends AbstractStatsTracker<FlowTableAndStatisticsMap, FlowTableAndStatisticsMap> {
+    private final Set<TableKey> privateTables = new ConcurrentSkipListSet<>();
+    private final Set<TableKey> tables = Collections.unmodifiableSet(privateTables);
+    private final OpendaylightFlowTableStatisticsService flowTableStatsService;
+
+    FlowTableStatsTracker(OpendaylightFlowTableStatisticsService flowTableStatsService, final FlowCapableContext context, long lifetimeNanos) {
+        super(context, lifetimeNanos);
+        this.flowTableStatsService = flowTableStatsService;
+    }
+
+    Set<TableKey> getTables() {
+        return tables;
+    }
+
+    @Override
+    protected void cleanupSingleStat(DataModificationTransaction trans, FlowTableAndStatisticsMap item) {
+        // TODO: do we want to do this?
+    }
+
+    @Override
+    protected FlowTableAndStatisticsMap updateSingleStat(DataModificationTransaction trans, FlowTableAndStatisticsMap item) {
+
+        InstanceIdentifier<Table> tableRef = getNodeIdentifierBuilder()
+                .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(item.getTableId().getValue())).build();
+
+        FlowTableStatisticsDataBuilder statisticsDataBuilder = new FlowTableStatisticsDataBuilder();
+        final FlowTableStatistics stats = new FlowTableStatisticsBuilder(item).build();
+        statisticsDataBuilder.setFlowTableStatistics(stats);
+
+        TableBuilder tableBuilder = new TableBuilder();
+        tableBuilder.setKey(new TableKey(item.getTableId().getValue()));
+        tableBuilder.addAugmentation(FlowTableStatisticsData.class, statisticsDataBuilder.build());
+        trans.putOperationalData(tableRef, tableBuilder.build());
+        return item;
+    }
+
+    public void request() {
+        if (flowTableStatsService != null) {
+            final GetFlowTablesStatisticsInputBuilder input = new GetFlowTablesStatisticsInputBuilder();
+            input.setNode(getNodeRef());
+
+            requestHelper(flowTableStatsService.getFlowTablesStatistics(input.build()));
+        }
+    }
+}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupDescStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupDescStatsTracker.java
new file mode 100644 (file)
index 0000000..8aebd6b
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright IBM Corporation, 2013.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetGroupDescriptionInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStatsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.desc.GroupDescBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class GroupDescStatsTracker extends AbstractListeningStatsTracker<GroupDescStats, GroupDescStats> {
+    private static final Logger logger = LoggerFactory.getLogger(GroupDescStatsTracker.class);
+    private final OpendaylightGroupStatisticsService groupStatsService;
+
+    public GroupDescStatsTracker(OpendaylightGroupStatisticsService groupStatsService, final FlowCapableContext context, final long lifetimeNanos) {
+        super(context, lifetimeNanos);
+        this.groupStatsService = groupStatsService;
+    }
+
+    @Override
+    protected GroupDescStats updateSingleStat(DataModificationTransaction trans, GroupDescStats item) {
+        GroupBuilder groupBuilder = new GroupBuilder();
+        GroupKey groupKey = new GroupKey(item.getGroupId());
+        groupBuilder.setKey(groupKey);
+
+        InstanceIdentifier<Group> groupRef = getNodeIdentifierBuilder()
+                .augmentation(FlowCapableNode.class).child(Group.class,groupKey).build();
+
+        NodeGroupDescStatsBuilder groupDesc= new NodeGroupDescStatsBuilder();
+        groupDesc.setGroupDesc(new GroupDescBuilder(item).build());
+
+        //Update augmented data
+        groupBuilder.addAugmentation(NodeGroupDescStats.class, groupDesc.build());
+
+        trans.putOperationalData(groupRef, groupBuilder.build());
+        return item;
+    }
+
+    @Override
+    protected void cleanupSingleStat(DataModificationTransaction trans, GroupDescStats item) {
+        InstanceIdentifier<NodeGroupDescStats> groupRef = getNodeIdentifierBuilder().augmentation(FlowCapableNode.class)
+                .child(Group.class, new GroupKey(item.getGroupId())).augmentation(NodeGroupDescStats.class).build();
+        trans.removeOperationalData(groupRef);
+    }
+
+    @Override
+    protected InstanceIdentifier<?> listenPath() {
+        return getNodeIdentifierBuilder().augmentation(FlowCapableNode.class).child(Group.class).build();
+    }
+
+    @Override
+    protected String statName() {
+        return "Group Descriptor";
+    }
+
+    public void request() {
+        if (groupStatsService != null) {
+            final GetGroupDescriptionInputBuilder input = new GetGroupDescriptionInputBuilder();
+            input.setNode(getNodeRef());
+
+            requestHelper(groupStatsService.getGroupDescription(input.build()));
+        }
+    }
+
+    @Override
+    public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+        for (InstanceIdentifier<?> key : change.getCreatedConfigurationData().keySet()) {
+            if (Group.class.equals(key.getTargetType())) {
+                logger.debug("Key {} triggered request", key);
+                request();
+            } else {
+                logger.debug("Ignoring key {}", key);
+            }
+        }
+
+        final DataModificationTransaction trans = startTransaction();
+        for (InstanceIdentifier<?> key : change.getRemovedConfigurationData()) {
+            if (Group.class.equals(key.getTargetType())) {
+                @SuppressWarnings("unchecked")
+                InstanceIdentifier<Group> group = (InstanceIdentifier<Group>)key;
+                InstanceIdentifier<?> del = InstanceIdentifier.builder(group).augmentation(NodeGroupDescStats.class).toInstance();
+                logger.debug("Key {} triggered remove of augmentation {}", key, del);
+
+                trans.removeOperationalData(del);
+            }
+        }
+        trans.commit();
+    }
+
+    @Override
+    public void start(final DataBrokerService dbs) {
+        if (groupStatsService == null) {
+            logger.debug("No Group Statistics service, not subscribing to groups on node {}", getNodeIdentifier());
+            return;
+        }
+
+        super.start(dbs);
+    }
+}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupStatsTracker.java
new file mode 100644 (file)
index 0000000..1af8e4e
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright IBM Corporation, 2013.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetAllGroupStatisticsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatistics;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.statistics.GroupStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+final class GroupStatsTracker extends AbstractListeningStatsTracker<GroupStats, GroupStats> {
+    private static final Logger logger = LoggerFactory.getLogger(GroupStatsTracker.class);
+    private final OpendaylightGroupStatisticsService groupStatsService;
+
+    GroupStatsTracker(OpendaylightGroupStatisticsService groupStatsService, FlowCapableContext context, long lifetimeNanos) {
+        super(context, lifetimeNanos);
+        this.groupStatsService = Preconditions.checkNotNull(groupStatsService);
+    }
+
+    @Override
+    protected void cleanupSingleStat(DataModificationTransaction trans, GroupStats item) {
+        InstanceIdentifier<NodeGroupStatistics> groupRef = getNodeIdentifierBuilder().augmentation(FlowCapableNode.class)
+                .child(Group.class, new GroupKey(item.getGroupId())).augmentation(NodeGroupStatistics.class).build();
+        trans.removeOperationalData(groupRef);
+    }
+
+    @Override
+    protected GroupStats updateSingleStat(DataModificationTransaction trans,
+            GroupStats item) {
+        GroupBuilder groupBuilder = new GroupBuilder();
+        GroupKey groupKey = new GroupKey(item.getGroupId());
+        groupBuilder.setKey(groupKey);
+
+        InstanceIdentifier<Group> groupRef = getNodeIdentifierBuilder().augmentation(FlowCapableNode.class)
+                .child(Group.class,groupKey).build();
+
+        NodeGroupStatisticsBuilder groupStatisticsBuilder= new NodeGroupStatisticsBuilder();
+        groupStatisticsBuilder.setGroupStatistics(new GroupStatisticsBuilder(item).build());
+
+        //Update augmented data
+        groupBuilder.addAugmentation(NodeGroupStatistics.class, groupStatisticsBuilder.build());
+        trans.putOperationalData(groupRef, groupBuilder.build());
+        return item;
+    }
+
+    @Override
+    protected InstanceIdentifier<?> listenPath() {
+        return getNodeIdentifierBuilder().augmentation(FlowCapableNode.class).child(Group.class).build();
+    }
+
+    @Override
+    protected String statName() {
+        return "Group";
+    }
+
+    public void request() {
+        final GetAllGroupStatisticsInputBuilder input = new GetAllGroupStatisticsInputBuilder();
+        input.setNode(getNodeRef());
+
+        requestHelper(groupStatsService.getAllGroupStatistics(input.build()));
+    }
+
+    @Override
+    public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+        final DataModificationTransaction trans = startTransaction();
+        for (InstanceIdentifier<?> key : change.getRemovedConfigurationData()) {
+            if (Group.class.equals(key.getTargetType())) {
+                @SuppressWarnings("unchecked")
+                InstanceIdentifier<Group> group = (InstanceIdentifier<Group>)key;
+                InstanceIdentifier<?> del = InstanceIdentifier.builder(group).augmentation(NodeGroupStatistics.class).toInstance();
+                logger.debug("Key {} triggered remove of augmentation {}", key, del);
+
+                trans.removeOperationalData(del);
+            }
+        }
+        trans.commit();
+    }
+
+    @Override
+    public void start(final DataBrokerService dbs) {
+        if (groupStatsService == null) {
+            logger.debug("No Group Statistics service, not subscribing to groups on node {}", getNodeIdentifier());
+            return;
+        }
+
+        super.start(dbs);
+    }
+}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterConfigStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterConfigStatsTracker.java
new file mode 100644 (file)
index 0000000..4b95925
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright IBM Corporation, 2013.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterConfigStatisticsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStatsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterConfigStatsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class MeterConfigStatsTracker extends AbstractListeningStatsTracker<MeterConfigStats, MeterConfigStats> {
+    private static final Logger logger = LoggerFactory.getLogger(MeterConfigStatsTracker.class);
+    private final OpendaylightMeterStatisticsService meterStatsService;
+
+    protected MeterConfigStatsTracker(OpendaylightMeterStatisticsService meterStatsService, final FlowCapableContext context, long lifetimeNanos) {
+        super(context, lifetimeNanos);
+        this.meterStatsService = meterStatsService;
+    }
+
+    @Override
+    protected void cleanupSingleStat(DataModificationTransaction trans, MeterConfigStats item) {
+        InstanceIdentifier<NodeMeterConfigStats> meterRef = getNodeIdentifierBuilder()
+                            .augmentation(FlowCapableNode.class)
+                            .child(Meter.class, new MeterKey(item.getMeterId()))
+                            .augmentation(NodeMeterConfigStats.class).build();
+        trans.removeOperationalData(meterRef);
+    }
+
+    @Override
+    protected MeterConfigStats updateSingleStat(DataModificationTransaction trans, MeterConfigStats item) {
+        MeterBuilder meterBuilder = new MeterBuilder();
+        MeterKey meterKey = new MeterKey(item.getMeterId());
+        meterBuilder.setKey(meterKey);
+
+        InstanceIdentifier<Meter> meterRef = getNodeIdentifierBuilder().augmentation(FlowCapableNode.class)
+                .child(Meter.class,meterKey).toInstance();
+
+        NodeMeterConfigStatsBuilder meterConfig = new NodeMeterConfigStatsBuilder();
+        meterConfig.setMeterConfigStats(new MeterConfigStatsBuilder(item).build());
+
+        //Update augmented data
+        meterBuilder.addAugmentation(NodeMeterConfigStats.class, meterConfig.build());
+
+        trans.putOperationalData(meterRef, meterBuilder.build());
+        return item;
+    }
+
+    public void request() {
+        if (meterStatsService != null) {
+            GetAllMeterConfigStatisticsInputBuilder input = new GetAllMeterConfigStatisticsInputBuilder();
+            input.setNode(getNodeRef());
+
+            requestHelper(meterStatsService.getAllMeterConfigStatistics(input.build()));
+        }
+    }
+
+    @Override
+    public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+        final DataModificationTransaction trans = startTransaction();
+
+        for (InstanceIdentifier<?> key : change.getRemovedConfigurationData()) {
+            if (Meter.class.equals(key.getTargetType())) {
+                @SuppressWarnings("unchecked")
+                InstanceIdentifier<Meter> meter = (InstanceIdentifier<Meter>)key;
+
+                InstanceIdentifier<?> nodeMeterStatisticsAugmentation =
+                        InstanceIdentifier.builder(meter).augmentation(NodeMeterConfigStats.class).toInstance();
+                trans.removeOperationalData(nodeMeterStatisticsAugmentation);
+            }
+        }
+
+        trans.commit();
+    }
+
+    @Override
+    protected InstanceIdentifier<?> listenPath() {
+        return getNodeIdentifierBuilder().augmentation(FlowCapableNode.class).child(Meter.class).build();
+    }
+
+    @Override
+    protected String statName() {
+        return "Meter Config";
+    }
+
+    @Override
+    public void start(final DataBrokerService dbs) {
+        if (meterStatsService == null) {
+            logger.debug("No Meter Statistics service, not subscribing to meter on node {}", getNodeIdentifier());
+            return;
+        }
+
+        super.start(dbs);
+    }
+}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterStatsTracker.java
new file mode 100644 (file)
index 0000000..091cbcc
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright IBM Corporation, 2013.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterStatisticsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatistics;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class MeterStatsTracker extends AbstractListeningStatsTracker<MeterStats, MeterStats> {
+    private static final Logger logger = LoggerFactory.getLogger(MeterStatsTracker.class);
+    private final OpendaylightMeterStatisticsService meterStatsService;
+
+    MeterStatsTracker(OpendaylightMeterStatisticsService meterStatsService, final FlowCapableContext context, long lifetimeNanos) {
+        super(context, lifetimeNanos);
+        this.meterStatsService = meterStatsService;
+    }
+
+    @Override
+    protected void cleanupSingleStat(DataModificationTransaction trans, MeterStats item) {
+        InstanceIdentifier<NodeMeterStatistics> meterRef = getNodeIdentifierBuilder()
+                            .augmentation(FlowCapableNode.class)
+                            .child(Meter.class,new MeterKey(item.getMeterId()))
+                            .augmentation(NodeMeterStatistics.class).build();
+        trans.removeOperationalData(meterRef);
+    }
+
+    @Override
+    protected MeterStats updateSingleStat(DataModificationTransaction trans, MeterStats item) {
+        MeterBuilder meterBuilder = new MeterBuilder();
+        MeterKey meterKey = new MeterKey(item.getMeterId());
+        meterBuilder.setKey(meterKey);
+
+        InstanceIdentifier<Meter> meterRef = getNodeIdentifierBuilder()
+                .augmentation(FlowCapableNode.class).child(Meter.class,meterKey).build();
+
+        NodeMeterStatisticsBuilder meterStatsBuilder= new NodeMeterStatisticsBuilder();
+        meterStatsBuilder.setMeterStatistics(new MeterStatisticsBuilder(item).build());
+
+        //Update augmented data
+        meterBuilder.addAugmentation(NodeMeterStatistics.class, meterStatsBuilder.build());
+        trans.putOperationalData(meterRef, meterBuilder.build());
+        return item;
+    }
+
+    public void request() {
+        if (meterStatsService != null) {
+            GetAllMeterStatisticsInputBuilder input = new GetAllMeterStatisticsInputBuilder();
+            input.setNode(getNodeRef());
+
+            requestHelper(meterStatsService.getAllMeterStatistics(input.build()));
+        }
+    }
+
+    @Override
+    public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+        for (InstanceIdentifier<?> key : change.getCreatedConfigurationData().keySet()) {
+            if (Meter.class.equals(key.getTargetType())) {
+                request();
+            }
+        }
+
+        final DataModificationTransaction trans = startTransaction();
+        for (InstanceIdentifier<?> key : change.getRemovedConfigurationData()) {
+            if (Meter.class.equals(key.getTargetType())) {
+                @SuppressWarnings("unchecked")
+                InstanceIdentifier<Meter> meter = (InstanceIdentifier<Meter>)key;
+
+                InstanceIdentifier<?> nodeMeterStatisticsAugmentation =
+                        InstanceIdentifier.builder(meter).augmentation(NodeMeterStatistics.class).toInstance();
+                trans.removeOperationalData(nodeMeterStatisticsAugmentation);
+            }
+        }
+        trans.commit();
+    }
+
+    @Override
+    protected InstanceIdentifier<?> listenPath() {
+        return getNodeIdentifierBuilder().augmentation(FlowCapableNode.class).child(Meter.class).build();
+    }
+
+    @Override
+    protected String statName() {
+        return "Meter";
+    }
+
+    @Override
+    public void start(final DataBrokerService dbs) {
+        if (meterStatsService == null) {
+            logger.debug("No Meter Statistics service, not subscribing to meters on node {}", getNodeIdentifier());
+            return;
+        }
+
+        super.start(dbs);
+    }
+}
index 6f58708e1b207edf898f606448147119ec3e106b..56b205216f2b8768fe66606808ec83c7906859e8 100644 (file)
@@ -7,63 +7,53 @@
  */
 package org.opendaylight.controller.md.statistics.manager;
 
-import java.util.Date;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionAware;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+
+import com.google.common.base.Preconditions;
 
 /**
- * Main responsibility of the class is to manage multipart response 
+ * Main responsibility of the class is to manage multipart response
  * for multipart request. It also handles the flow aggregate request
- * and response mapping. 
+ * and response mapping.
  * @author avishnoi@in.ibm.com
  *
  */
-public class MultipartMessageManager {
-
+class MultipartMessageManager {
     /*
-     *  Map for tx id and type of request, to keep track of all the request sent 
-     *  by Statistics Manager. Statistics Manager won't entertain any multipart 
-     *  response for which it didn't send the request.  
+     *  Map for tx id and type of request, to keep track of all the request sent
+     *  by Statistics Manager. Statistics Manager won't entertain any multipart
+     *  response for which it didn't send the request.
      */
-    
-    private static Map<TxIdEntry,Date> txIdToRequestTypeMap = new ConcurrentHashMap<TxIdEntry,Date>();
+    private final Map<TxIdEntry,Long> txIdToRequestTypeMap = new ConcurrentHashMap<>();
     /*
      * Map to keep track of the request tx id for flow table statistics request.
      * Because flow table statistics multi part response do not contains the table id.
      */
-    private static Map<TxIdEntry,Short> txIdTotableIdMap = new ConcurrentHashMap<TxIdEntry,Short>();
-    
-    private final int NUMBER_OF_WAIT_CYCLES =2;
+    private final Map<TxIdEntry,Short> txIdTotableIdMap = new ConcurrentHashMap<>();
+    private final long lifetimeNanos;
+
+    public MultipartMessageManager(long lifetimeNanos) {
+        this.lifetimeNanos = lifetimeNanos;
+    }
 
-    class TxIdEntry{
+    private static final class TxIdEntry {
         private final TransactionId txId;
-        private final NodeId nodeId;
-        private final StatsRequestType requestType;
-        
-        public TxIdEntry(NodeId nodeId, TransactionId txId, StatsRequestType requestType){
+
+        public TxIdEntry(TransactionId txId) {
             this.txId = txId;
-            this.nodeId = nodeId;
-            this.requestType = requestType;
         }
         public TransactionId getTxId() {
             return txId;
         }
-        public NodeId getNodeId() {
-            return nodeId;
-        }
-        public StatsRequestType getRequestType() {
-            return requestType;
-        }
         @Override
         public int hashCode() {
             final int prime = 31;
             int result = 1;
-            result = prime * result + getOuterType().hashCode();
-            result = prime * result + ((nodeId == null) ? 0 : nodeId.hashCode());
             result = prime * result + ((txId == null) ? 0 : txId.hashCode());
             return result;
         }
@@ -79,16 +69,7 @@ public class MultipartMessageManager {
                 return false;
             }
             TxIdEntry other = (TxIdEntry) obj;
-            if (!getOuterType().equals(other.getOuterType())) {
-                return false;
-            }
-            if (nodeId == null) {
-                if (other.nodeId != null) {
-                    return false;
-                }
-            } else if (!nodeId.equals(other.nodeId)) {
-                return false;
-            }
+
             if (txId == null) {
                 if (other.txId != null) {
                     return false;
@@ -98,75 +79,60 @@ public class MultipartMessageManager {
             }
             return true;
         }
-        private MultipartMessageManager getOuterType() {
-            return MultipartMessageManager.this;
-        }
+
         @Override
         public String toString() {
-            return "TxIdEntry [txId=" + txId + ", nodeId=" + nodeId + ", requestType=" + requestType + "]";
+            return "TxIdEntry [txId=" + txId + ']';
         }
     }
 
-    public MultipartMessageManager(){}
-    
-    public Short getTableIdForTxId(NodeId nodeId,TransactionId id){
-        
-        return txIdTotableIdMap.get(new TxIdEntry(nodeId,id,null));
-        
-    }
-    
-    public void setTxIdAndTableIdMapEntry(NodeId nodeId, TransactionId id,Short tableId){
-        if(id == null)
-            return;
-        txIdTotableIdMap.put(new TxIdEntry(nodeId,id,null), tableId);
+    public void recordExpectedTableTransaction(TransactionId id, Short tableId) {
+        recordExpectedTransaction(id);
+        txIdTotableIdMap.put(new TxIdEntry(id), Preconditions.checkNotNull(tableId));
     }
-    
-    public boolean isRequestTxIdExist(NodeId nodeId, TransactionId id, Boolean moreRepliesToFollow){
-        TxIdEntry entry = new TxIdEntry(nodeId,id,null);
-        if(moreRepliesToFollow.booleanValue()){
-            return txIdToRequestTypeMap.containsKey(entry);
-        }else{
-            return txIdToRequestTypeMap.remove(entry)==null?false:true;
+
+    public Short isExpectedTableTransaction(TransactionAware transaction, Boolean more) {
+        if (!isExpectedTransaction(transaction, more)) {
+            return null;
+        }
+
+        final TxIdEntry key = new TxIdEntry(transaction.getTransactionId());
+        if (more != null && more.booleanValue()) {
+            return txIdTotableIdMap.get(key);
+        } else {
+            return txIdTotableIdMap.remove(key);
         }
     }
-    public void addTxIdToRequestTypeEntry (NodeId nodeId, TransactionId id,StatsRequestType type){
-        if(id == null)
-            return;
-        TxIdEntry entry = new TxIdEntry(nodeId,id,type);
+
+    public void recordExpectedTransaction(TransactionId id) {
+        TxIdEntry entry = new TxIdEntry(Preconditions.checkNotNull(id));
         txIdToRequestTypeMap.put(entry, getExpiryTime());
     }
-    public boolean removeTxId(NodeId nodeId, TransactionId id){
-        TxIdEntry entry = new TxIdEntry(nodeId,id,null);
-        return txIdToRequestTypeMap.remove(entry)==null?false:true;
-    }
-    
-    private Date getExpiryTime(){
-        Date expires = new Date();
-        expires.setTime(expires.getTime()+StatisticsProvider.STATS_THREAD_EXECUTION_TIME*NUMBER_OF_WAIT_CYCLES);
-        return expires;
+
+    public boolean isExpectedTransaction(TransactionAware transaction, Boolean more) {
+        TxIdEntry entry = new TxIdEntry(transaction.getTransactionId());
+        if (more != null && more.booleanValue()) {
+            return txIdToRequestTypeMap.containsKey(entry);
+        } else {
+            return txIdToRequestTypeMap.remove(entry) != null;
+        }
     }
 
-    public enum StatsRequestType{
-        ALL_FLOW,
-        AGGR_FLOW,
-        ALL_PORT,
-        ALL_FLOW_TABLE,
-        ALL_QUEUE_STATS,
-        ALL_GROUP,
-        ALL_METER,
-        GROUP_DESC,
-        METER_CONFIG
+    private Long getExpiryTime() {
+        return System.nanoTime() + lifetimeNanos;
     }
-    
-    public void cleanStaleTransactionIds(){
+
+    public void cleanStaleTransactionIds() {
+        final long now = System.nanoTime();
+
         for (Iterator<TxIdEntry> it = txIdToRequestTypeMap.keySet().iterator();it.hasNext();){
             TxIdEntry txIdEntry = it.next();
-            Date now = new Date();
-            Date expiryTime = txIdToRequestTypeMap.get(txIdEntry);
-            if(now.after(expiryTime)){
+
+            Long expiryTime = txIdToRequestTypeMap.get(txIdEntry);
+            if(now > expiryTime){
                 it.remove();
                 txIdTotableIdMap.remove(txIdEntry);
-            }            
+            }
         }
     }
 }
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeConnectorStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeConnectorStatsTracker.java
new file mode 100644 (file)
index 0000000..00bd274
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright IBM Corporation, 2013.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllNodeConnectorsStatisticsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.flow.capable.node.connector.statistics.FlowCapableNodeConnectorStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class NodeConnectorStatsTracker extends AbstractStatsTracker<NodeConnectorStatisticsAndPortNumberMap, NodeConnectorStatisticsAndPortNumberMap> {
+    private static final Logger logger = LoggerFactory.getLogger(NodeConnectorStatsTracker.class);
+    private final OpendaylightPortStatisticsService portStatsService;
+
+    NodeConnectorStatsTracker(final OpendaylightPortStatisticsService portStatsService, final FlowCapableContext context, long lifetimeNanos) {
+        super(context, lifetimeNanos);
+        this.portStatsService = portStatsService;
+    }
+
+    @Override
+    protected void cleanupSingleStat(DataModificationTransaction trans, NodeConnectorStatisticsAndPortNumberMap item) {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
+    protected NodeConnectorStatisticsAndPortNumberMap updateSingleStat(DataModificationTransaction trans, NodeConnectorStatisticsAndPortNumberMap item) {
+        FlowCapableNodeConnectorStatisticsBuilder statisticsBuilder
+                                        = new FlowCapableNodeConnectorStatisticsBuilder();
+        statisticsBuilder.setBytes(item.getBytes());
+        statisticsBuilder.setCollisionCount(item.getCollisionCount());
+        statisticsBuilder.setDuration(item.getDuration());
+        statisticsBuilder.setPackets(item.getPackets());
+        statisticsBuilder.setReceiveCrcError(item.getReceiveCrcError());
+        statisticsBuilder.setReceiveDrops(item.getReceiveDrops());
+        statisticsBuilder.setReceiveErrors(item.getReceiveErrors());
+        statisticsBuilder.setReceiveFrameError(item.getReceiveFrameError());
+        statisticsBuilder.setReceiveOverRunError(item.getReceiveOverRunError());
+        statisticsBuilder.setTransmitDrops(item.getTransmitDrops());
+        statisticsBuilder.setTransmitErrors(item.getTransmitErrors());
+
+        //Augment data to the node-connector
+        FlowCapableNodeConnectorStatisticsDataBuilder statisticsDataBuilder =
+                new FlowCapableNodeConnectorStatisticsDataBuilder();
+
+        statisticsDataBuilder.setFlowCapableNodeConnectorStatistics(statisticsBuilder.build());
+
+        InstanceIdentifier<NodeConnector> nodeConnectorRef = getNodeIdentifierBuilder()
+                .child(NodeConnector.class, new NodeConnectorKey(item.getNodeConnectorId())).build();
+
+        // FIXME: can we bypass this read?
+        NodeConnector nodeConnector = (NodeConnector)trans.readOperationalData(nodeConnectorRef);
+        if(nodeConnector != null){
+            final FlowCapableNodeConnectorStatisticsData stats = statisticsDataBuilder.build();
+            logger.debug("Augmenting port statistics {} to port {}",stats,nodeConnectorRef.toString());
+            NodeConnectorBuilder nodeConnectorBuilder = new NodeConnectorBuilder();
+            nodeConnectorBuilder.addAugmentation(FlowCapableNodeConnectorStatisticsData.class, stats);
+            trans.putOperationalData(nodeConnectorRef, nodeConnectorBuilder.build());
+        }
+
+        return item;
+    }
+
+    public void request() {
+        if (portStatsService != null) {
+            final GetAllNodeConnectorsStatisticsInputBuilder input = new GetAllNodeConnectorsStatisticsInputBuilder();
+            input.setNode(getNodeRef());
+
+            requestHelper(portStatsService.getAllNodeConnectorsStatistics(input.build()));
+        }
+    }
+}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsAger.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsAger.java
deleted file mode 100644 (file)
index 4ecd620..0000000
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
- * Copyright IBM Corporation, 2013.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.md.statistics.manager;
-
-import java.util.Date;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStats;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatistics;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
-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.meter.statistics.rev131111.NodeMeterConfigStats;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatistics;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsData;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
-
-/**
- * Main responsibility of this class to clean up all the stale statistics data
- * associated to Flow,Meter,Group,Queue.
- * @author avishnoi@in.ibm.com
- *
- */
-public class NodeStatisticsAger {
-    
-    private final int NUMBER_OF_WAIT_CYCLES =2;
-
-    private final StatisticsProvider statisticsProvider;
-
-    private final NodeKey targetNodeKey;
-    
-    private final Map<GroupDescStats,Date> groupDescStatsUpdate
-                = new ConcurrentHashMap<GroupDescStats,Date>();
-    
-    private final Map<MeterConfigStats,Date> meterConfigStatsUpdate
-                = new ConcurrentHashMap<MeterConfigStats,Date>();
-    
-    private final Map<FlowEntry,Date> flowStatsUpdate
-                = new ConcurrentHashMap<FlowEntry,Date>();
-    
-    private final Map<QueueEntry,Date> queuesStatsUpdate 
-                = new ConcurrentHashMap<QueueEntry,Date>();
-    
-    public NodeStatisticsAger(StatisticsProvider statisticsProvider, NodeKey nodeKey){
-        this.targetNodeKey = nodeKey;
-        this.statisticsProvider = statisticsProvider;
-    }
-
-    public class FlowEntry{
-        private final Short tableId;
-        private final Flow flow;
-        
-        public FlowEntry(Short tableId, Flow flow){
-            this.tableId = tableId;
-            this.flow = flow;
-        }
-
-        public Short getTableId() {
-            return tableId;
-        }
-
-        public Flow getFlow() {
-            return flow;
-        }
-
-        @Override
-        public int hashCode() {
-            final int prime = 31;
-            int result = 1;
-            result = prime * result + getOuterType().hashCode();
-            result = prime * result + ((flow == null) ? 0 : flow.hashCode());
-            result = prime * result + ((tableId == null) ? 0 : tableId.hashCode());
-            return result;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj)
-                return true;
-            if (obj == null)
-                return false;
-            if (getClass() != obj.getClass())
-                return false;
-            FlowEntry other = (FlowEntry) obj;
-            if (!getOuterType().equals(other.getOuterType()))
-                return false;
-            if (flow == null) {
-                if (other.flow != null)
-                    return false;
-            } else if (!flow.equals(other.flow))
-                return false;
-            if (tableId == null) {
-                if (other.tableId != null)
-                    return false;
-            } else if (!tableId.equals(other.tableId))
-                return false;
-            return true;
-        }
-
-        private NodeStatisticsAger getOuterType() {
-            return NodeStatisticsAger.this;
-        }
-        
-    }
-    
-    public class QueueEntry{
-        private final NodeConnectorId nodeConnectorId;
-        private final QueueId queueId;
-        public QueueEntry(NodeConnectorId ncId, QueueId queueId){
-            this.nodeConnectorId = ncId;
-            this.queueId = queueId;
-        }
-        public NodeConnectorId getNodeConnectorId() {
-            return nodeConnectorId;
-        }
-        public QueueId getQueueId() {
-            return queueId;
-        }
-        @Override
-        public int hashCode() {
-            final int prime = 31;
-            int result = 1;
-            result = prime * result + getOuterType().hashCode();
-            result = prime * result + ((nodeConnectorId == null) ? 0 : nodeConnectorId.hashCode());
-            result = prime * result + ((queueId == null) ? 0 : queueId.hashCode());
-            return result;
-        }
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj) {
-                return true;
-            }
-            if (obj == null) {
-                return false;
-            }
-            if (!(obj instanceof QueueEntry)) {
-                return false;
-            }
-            QueueEntry other = (QueueEntry) obj;
-            if (!getOuterType().equals(other.getOuterType())) {
-                return false;
-            }
-            if (nodeConnectorId == null) {
-                if (other.nodeConnectorId != null) {
-                    return false;
-                }
-            } else if (!nodeConnectorId.equals(other.nodeConnectorId)) {
-                return false;
-            }
-            if (queueId == null) {
-                if (other.queueId != null) {
-                    return false;
-                }
-            } else if (!queueId.equals(other.queueId)) {
-                return false;
-            }
-            return true;
-        }
-        private NodeStatisticsAger getOuterType() {
-            return NodeStatisticsAger.this;
-        }
-    }
-    
-    public NodeKey getTargetNodeKey() {
-        return targetNodeKey;
-    }
-
-    public Map<GroupDescStats, Date> getGroupDescStatsUpdate() {
-        return groupDescStatsUpdate;
-    }
-
-    public Map<MeterConfigStats, Date> getMeterConfigStatsUpdate() {
-        return meterConfigStatsUpdate;
-    }
-
-    public Map<FlowEntry, Date> getFlowStatsUpdate() {
-        return flowStatsUpdate;
-    }
-
-    public Map<QueueEntry, Date> getQueuesStatsUpdate() {
-        return queuesStatsUpdate;
-    }
-
-    public void updateGroupDescStats(List<GroupDescStats> list){
-        Date expiryTime = getExpiryTime();
-        for(GroupDescStats groupDescStats : list)
-            this.groupDescStatsUpdate.put(groupDescStats, expiryTime);
-    }
-    
-    public void updateMeterConfigStats(List<MeterConfigStats> list){
-        Date expiryTime = getExpiryTime();
-        for(MeterConfigStats meterConfigStats: list)
-            this.meterConfigStatsUpdate.put(meterConfigStats, expiryTime);
-    }
-    
-    public void  updateFlowStats(FlowEntry flowEntry){
-        this.flowStatsUpdate.put(flowEntry, getExpiryTime());
-    }
-    public void updateQueueStats(QueueEntry queueEntry){
-        this.queuesStatsUpdate.put(queueEntry, getExpiryTime());
-    }
-    
-    private Date getExpiryTime(){
-        Date expires = new Date();
-        expires.setTime(expires.getTime()+StatisticsProvider.STATS_THREAD_EXECUTION_TIME*NUMBER_OF_WAIT_CYCLES);
-        return expires;
-    }
-    
-    public void cleanStaleStatistics(){
-        //Clean stale statistics related to group 
-        for (Iterator<GroupDescStats> it = this.groupDescStatsUpdate.keySet().iterator();it.hasNext();){
-            GroupDescStats groupDescStats = it.next();
-            Date now = new Date();
-            Date expiryTime = this.groupDescStatsUpdate.get(groupDescStats);
-            if(now.after(expiryTime)){
-                cleanGroupStatsFromDataStore(groupDescStats );
-                it.remove();
-            }
-        }
-        
-        //Clean stale statistics related to meter 
-        for (Iterator<MeterConfigStats> it = this.meterConfigStatsUpdate.keySet().iterator();it.hasNext();){
-            MeterConfigStats meterConfigStats = it.next();
-            Date now = new Date();
-            Date expiryTime = this.meterConfigStatsUpdate.get(meterConfigStats);
-            if(now.after(expiryTime)){
-                cleanMeterStatsFromDataStore(meterConfigStats);
-                it.remove();
-            }            
-        }
-        
-        //Clean stale statistics related to flow 
-        for (Iterator<FlowEntry> it = this.flowStatsUpdate.keySet().iterator();it.hasNext();){
-            FlowEntry flowEntry = it.next();
-            Date now = new Date();
-            Date expiryTime = this.flowStatsUpdate.get(flowEntry);
-            if(now.after(expiryTime)){
-                cleanFlowStatsFromDataStore(flowEntry);
-                it.remove();
-            }            
-        }
-
-        //Clean stale statistics related to queue
-        for (Iterator<QueueEntry> it = this.queuesStatsUpdate.keySet().iterator();it.hasNext();){
-            QueueEntry queueEntry = it.next();
-            Date now = new Date();
-            Date expiryTime = this.queuesStatsUpdate.get(queueEntry);
-            if(now.after(expiryTime)){
-                cleanQueueStatsFromDataStore(queueEntry);
-                it.remove();
-            }            
-        }
-        
-    }
-
-    private void cleanQueueStatsFromDataStore(QueueEntry queueEntry) {
-        InstanceIdentifier<?> queueRef 
-                        = InstanceIdentifier.builder(Nodes.class)
-                                            .child(Node.class, this.targetNodeKey)
-                                            .child(NodeConnector.class, new NodeConnectorKey(queueEntry.getNodeConnectorId()))
-                                            .augmentation(FlowCapableNodeConnector.class)
-                                            .child(Queue.class, new QueueKey(queueEntry.getQueueId()))
-                                            .augmentation(FlowCapableNodeConnectorQueueStatisticsData.class).toInstance();
-        cleanStaleStatisticsFromDataStore(queueRef);
-    }
-
-    private void cleanFlowStatsFromDataStore(FlowEntry flowEntry) {
-        InstanceIdentifier<?> flowRef 
-                        = InstanceIdentifier.builder(Nodes.class).child(Node.class, this.targetNodeKey)
-                                            .augmentation(FlowCapableNode.class)
-                                            .child(Table.class, new TableKey(flowEntry.getTableId()))
-                                            .child(Flow.class,flowEntry.getFlow().getKey())
-                                            .augmentation(FlowStatisticsData.class).toInstance();
-        
-        cleanStaleStatisticsFromDataStore(flowRef);
-        
-    }
-
-    private void cleanMeterStatsFromDataStore(MeterConfigStats meterConfigStats) {
-        InstanceIdentifierBuilder<Meter> meterRef 
-                        = InstanceIdentifier.builder(Nodes.class).child(Node.class,this.targetNodeKey)
-                                            .augmentation(FlowCapableNode.class)
-                                            .child(Meter.class,new MeterKey(meterConfigStats.getMeterId()));
-        
-        InstanceIdentifier<?> nodeMeterConfigStatsAugmentation = meterRef.augmentation(NodeMeterConfigStats.class).toInstance();
-                                            
-        cleanStaleStatisticsFromDataStore(nodeMeterConfigStatsAugmentation);
-        
-        InstanceIdentifier<?> nodeMeterStatisticsAugmentation = meterRef.augmentation(NodeMeterStatistics.class).toInstance();
-        
-        cleanStaleStatisticsFromDataStore(nodeMeterStatisticsAugmentation);
-        
-    }
-
-    private void cleanGroupStatsFromDataStore(GroupDescStats groupDescStats) {
-        InstanceIdentifierBuilder<Group> groupRef 
-                        = InstanceIdentifier.builder(Nodes.class).child(Node.class,this.targetNodeKey)
-                                            .augmentation(FlowCapableNode.class)
-                                            .child(Group.class,new GroupKey(groupDescStats.getGroupId()));
-        
-        InstanceIdentifier<?> nodeGroupDescStatsAugmentation = groupRef.augmentation(NodeGroupDescStats.class).toInstance();
-        
-        cleanStaleStatisticsFromDataStore(nodeGroupDescStatsAugmentation);
-
-        InstanceIdentifier<?> nodeGroupStatisticsAugmentation = groupRef.augmentation(NodeGroupStatistics.class).toInstance();
-        
-        cleanStaleStatisticsFromDataStore(nodeGroupStatisticsAugmentation);
-    }
-    
-    private void cleanStaleStatisticsFromDataStore(InstanceIdentifier<? extends DataObject> ii){
-        if(ii != null){
-            DataModificationTransaction it = this.statisticsProvider.startChange();
-            it.removeOperationalData(ii);
-            it.commit();
-        }
-    }
-}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsHandler.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsHandler.java
new file mode 100644 (file)
index 0000000..6796b4e
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * Copyright IBM Corporation, 2013.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.TimeUnit;
+
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+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.statistics.rev130819.AggregateFlowStatisticsData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.aggregate.flow.statistics.AggregateFlowStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionAware;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeatures;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeaturesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeaturesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupFeatures;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeatures;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeaturesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeaturesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterFeatures;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.AggregateFlowStatistics;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMap;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * This class handles the lifecycle of per-node statistics. It receives data
+ * from StatisticsListener, stores it in the data store and keeps track of
+ * when the data should be removed.
+ *
+ * @author avishnoi@in.ibm.com
+ */
+public final class NodeStatisticsHandler implements AutoCloseable, FlowCapableContext {
+    private static final Logger logger = LoggerFactory.getLogger(NodeStatisticsHandler.class);
+
+    private static final long STATS_COLLECTION_MILLIS = TimeUnit.SECONDS.toMillis(15);
+    private static final long FIRST_COLLECTION_MILLIS = TimeUnit.SECONDS.toMillis(5);
+    private static final int NUMBER_OF_WAIT_CYCLES = 2;
+
+    private final MultipartMessageManager msgManager;
+    private final InstanceIdentifier<Node> targetNodeIdentifier;
+    private final FlowStatsTracker flowStats;
+    private final FlowTableStatsTracker flowTableStats;
+    private final GroupDescStatsTracker groupDescStats;
+    private final GroupStatsTracker groupStats;
+    private final MeterConfigStatsTracker meterConfigStats;
+    private final MeterStatsTracker meterStats;
+    private final NodeConnectorStatsTracker nodeConnectorStats;
+    private final QueueStatsTracker queueStats;
+    private final DataProviderService dps;
+    private final NodeRef targetNodeRef;
+    private final NodeKey targetNodeKey;
+    private final TimerTask task = new TimerTask() {
+        @Override
+        public void run() {
+            requestPeriodicStatistics();
+            cleanStaleStatistics();
+        }
+    };
+
+    public NodeStatisticsHandler(final DataProviderService dps, final NodeKey nodeKey,
+            final OpendaylightFlowStatisticsService flowStatsService,
+            final OpendaylightFlowTableStatisticsService flowTableStatsService,
+            final OpendaylightGroupStatisticsService groupStatsService,
+            final OpendaylightMeterStatisticsService meterStatsService,
+            final OpendaylightPortStatisticsService portStatsService,
+            final OpendaylightQueueStatisticsService queueStatsService) {
+        this.dps = Preconditions.checkNotNull(dps);
+        this.targetNodeKey = Preconditions.checkNotNull(nodeKey);
+        this.targetNodeIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).build();
+        this.targetNodeRef = new NodeRef(targetNodeIdentifier);
+
+        final long lifetimeNanos = TimeUnit.MILLISECONDS.toNanos(STATS_COLLECTION_MILLIS * NUMBER_OF_WAIT_CYCLES);
+
+        msgManager = new MultipartMessageManager(lifetimeNanos);
+        flowStats = new FlowStatsTracker(flowStatsService, this, lifetimeNanos);
+        flowTableStats = new FlowTableStatsTracker(flowTableStatsService, this, lifetimeNanos);
+        groupDescStats = new GroupDescStatsTracker(groupStatsService, this, lifetimeNanos);
+        groupStats = new GroupStatsTracker(groupStatsService, this, lifetimeNanos);
+        meterConfigStats = new MeterConfigStatsTracker(meterStatsService, this, lifetimeNanos);
+        meterStats = new MeterStatsTracker(meterStatsService, this, lifetimeNanos);
+        nodeConnectorStats = new NodeConnectorStatsTracker(portStatsService, this, lifetimeNanos);
+        queueStats = new QueueStatsTracker(queueStatsService, this, lifetimeNanos);
+    }
+
+    public NodeKey getTargetNodeKey() {
+        return targetNodeKey;
+    }
+
+    @Override
+    public InstanceIdentifier<Node> getNodeIdentifier() {
+        return targetNodeIdentifier;
+    }
+
+    @Override
+    public NodeRef getNodeRef() {
+        return targetNodeRef;
+    }
+
+    @Override
+    public DataModificationTransaction startDataModification() {
+        return dps.beginTransaction();
+    }
+
+    public synchronized void updateGroupDescStats(TransactionAware transaction, Boolean more, List<GroupDescStats> list) {
+        if (msgManager.isExpectedTransaction(transaction, more)) {
+            groupDescStats.updateStats(list);
+        }
+    }
+
+    public synchronized void updateGroupStats(TransactionAware transaction, Boolean more, List<GroupStats> list) {
+        if (msgManager.isExpectedTransaction(transaction, more)) {
+            groupStats.updateStats(list);
+        }
+    }
+
+    public synchronized void updateMeterConfigStats(TransactionAware transaction, Boolean more, List<MeterConfigStats> list) {
+        if (msgManager.isExpectedTransaction(transaction, more)) {
+            meterConfigStats.updateStats(list);
+        }
+    }
+
+    public synchronized void updateMeterStats(TransactionAware transaction, Boolean more, List<MeterStats> list) {
+        if (msgManager.isExpectedTransaction(transaction, more)) {
+            meterStats.updateStats(list);
+        }
+    }
+
+    public synchronized void updateQueueStats(TransactionAware transaction, Boolean more, List<QueueIdAndStatisticsMap> list) {
+        if (msgManager.isExpectedTransaction(transaction, more)) {
+            queueStats.updateStats(list);
+        }
+    }
+
+    public synchronized void updateFlowTableStats(TransactionAware transaction, Boolean more, List<FlowTableAndStatisticsMap> list) {
+        if (msgManager.isExpectedTransaction(transaction, more)) {
+            flowTableStats.updateStats(list);
+        }
+    }
+
+    public synchronized void updateNodeConnectorStats(TransactionAware transaction, Boolean more, List<NodeConnectorStatisticsAndPortNumberMap> list) {
+        if (msgManager.isExpectedTransaction(transaction, more)) {
+            nodeConnectorStats.updateStats(list);
+        }
+    }
+
+    public synchronized void updateAggregateFlowStats(TransactionAware transaction, Boolean more, AggregateFlowStatistics flowStats) {
+        final Short tableId = msgManager.isExpectedTableTransaction(transaction, more);
+        if (tableId != null) {
+            final DataModificationTransaction trans = dps.beginTransaction();
+            InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
+                    .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
+
+            AggregateFlowStatisticsDataBuilder aggregateFlowStatisticsDataBuilder = new AggregateFlowStatisticsDataBuilder();
+            AggregateFlowStatisticsBuilder aggregateFlowStatisticsBuilder = new AggregateFlowStatisticsBuilder(flowStats);
+
+            aggregateFlowStatisticsDataBuilder.setAggregateFlowStatistics(aggregateFlowStatisticsBuilder.build());
+
+            logger.debug("Augment aggregate statistics: {} for table {} on Node {}",
+                    aggregateFlowStatisticsBuilder.build().toString(),tableId,targetNodeKey);
+
+            TableBuilder tableBuilder = new TableBuilder();
+            tableBuilder.setKey(new TableKey(tableId));
+            tableBuilder.addAugmentation(AggregateFlowStatisticsData.class, aggregateFlowStatisticsDataBuilder.build());
+            trans.putOperationalData(tableRef, tableBuilder.build());
+
+            trans.commit();
+        }
+    }
+
+    public synchronized void updateFlowStats(TransactionAware transaction, Boolean more, List<FlowAndStatisticsMapList> list) {
+        if (msgManager.isExpectedTransaction(transaction, more)) {
+            flowStats.updateStats(list);
+        }
+    }
+
+    public synchronized void updateGroupFeatures(GroupFeatures notification) {
+        final DataModificationTransaction trans = dps.beginTransaction();
+
+        final NodeBuilder nodeData = new NodeBuilder();
+        nodeData.setKey(targetNodeKey);
+
+        NodeGroupFeaturesBuilder nodeGroupFeatures = new NodeGroupFeaturesBuilder();
+        GroupFeaturesBuilder groupFeatures = new GroupFeaturesBuilder(notification);
+        nodeGroupFeatures.setGroupFeatures(groupFeatures.build());
+
+        //Update augmented data
+        nodeData.addAugmentation(NodeGroupFeatures.class, nodeGroupFeatures.build());
+        trans.putOperationalData(targetNodeIdentifier, nodeData.build());
+
+        // FIXME: should we be tracking this data?
+        trans.commit();
+    }
+
+    public synchronized void updateMeterFeatures(MeterFeatures features) {
+        final DataModificationTransaction trans = dps.beginTransaction();
+
+        final NodeBuilder nodeData = new NodeBuilder();
+        nodeData.setKey(targetNodeKey);
+
+        NodeMeterFeaturesBuilder nodeMeterFeatures = new NodeMeterFeaturesBuilder();
+        MeterFeaturesBuilder meterFeature = new MeterFeaturesBuilder(features);
+        nodeMeterFeatures.setMeterFeatures(meterFeature.build());
+
+        //Update augmented data
+        nodeData.addAugmentation(NodeMeterFeatures.class, nodeMeterFeatures.build());
+        trans.putOperationalData(targetNodeIdentifier, nodeData.build());
+
+        // FIXME: should we be tracking this data?
+        trans.commit();
+    }
+
+    public synchronized void cleanStaleStatistics() {
+        final DataModificationTransaction trans = dps.beginTransaction();
+        final long now = System.nanoTime();
+
+        flowStats.cleanup(trans, now);
+        groupDescStats.cleanup(trans, now);
+        groupStats.cleanup(trans, now);
+        meterConfigStats.cleanup(trans, now);
+        meterStats.cleanup(trans, now);
+        nodeConnectorStats.cleanup(trans, now);
+        queueStats.cleanup(trans, now);
+        msgManager.cleanStaleTransactionIds();
+
+        trans.commit();
+    }
+
+    public synchronized void requestPeriodicStatistics() {
+        logger.debug("Send requests for statistics collection to node : {}", targetNodeKey);
+
+        flowTableStats.request();
+
+        // FIXME: it does not make sense to trigger this before sendAllFlowTablesStatisticsRequest()
+        //        comes back -- we do not have any tables anyway.
+        final Collection<TableKey> tables = flowTableStats.getTables();
+        logger.debug("Node {} supports {} table(s)", targetNodeKey, tables.size());
+        for (final TableKey key : tables) {
+            logger.debug("Send aggregate stats request for flow table {} to node {}", key.getId(), targetNodeKey);
+            flowStats.requestAggregateFlows(key);
+        }
+
+        flowStats.requestAllFlowsAllTables();
+        nodeConnectorStats.request();
+        groupStats.request();
+        groupDescStats.request();
+        meterStats.request();
+        meterConfigStats.request();
+        queueStats.request();
+    }
+
+    public synchronized void start(final Timer timer) {
+        flowStats.start(dps);
+        groupDescStats.start(dps);
+        groupStats.start(dps);
+        meterConfigStats.start(dps);
+        meterStats.start(dps);
+        queueStats.start(dps);
+
+        timer.schedule(task, (long) (Math.random() * FIRST_COLLECTION_MILLIS), STATS_COLLECTION_MILLIS);
+
+        logger.debug("Statistics handler for node started with base interval {}ms", STATS_COLLECTION_MILLIS);
+
+        requestPeriodicStatistics();
+    }
+
+    @Override
+    public synchronized void close() {
+        task.cancel();
+        flowStats.close();
+        groupDescStats.close();
+        groupStats.close();
+        meterConfigStats.close();
+        meterStats.close();
+        queueStats.close();
+
+        logger.debug("Statistics handler for {} shut down", targetNodeKey.getId());
+    }
+
+    @Override
+    public void registerTransaction(TransactionId id) {
+        msgManager.recordExpectedTransaction(id);
+        logger.debug("Transaction {} for node {} sent successfully", id, targetNodeKey);
+    }
+
+    @Override
+    public void registerTableTransaction(final TransactionId id, final Short table) {
+        msgManager.recordExpectedTableTransaction(id, table);
+        logger.debug("Transaction {} for node {} table {} sent successfully", id, targetNodeKey, table);
+    }
+}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsEntry.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsEntry.java
new file mode 100644 (file)
index 0000000..d1f2529
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright IBM Corporation, 2013.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+
+final class QueueStatsEntry {
+    private final NodeConnectorId nodeConnectorId;
+    private final QueueId queueId;
+    public QueueStatsEntry(NodeConnectorId ncId, QueueId queueId){
+        this.nodeConnectorId = ncId;
+        this.queueId = queueId;
+    }
+    public NodeConnectorId getNodeConnectorId() {
+        return nodeConnectorId;
+    }
+    public QueueId getQueueId() {
+        return queueId;
+    }
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((nodeConnectorId == null) ? 0 : nodeConnectorId.hashCode());
+        result = prime * result + ((queueId == null) ? 0 : queueId.hashCode());
+        return result;
+    }
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof QueueStatsEntry)) {
+            return false;
+        }
+        QueueStatsEntry other = (QueueStatsEntry) obj;
+        if (nodeConnectorId == null) {
+            if (other.nodeConnectorId != null) {
+                return false;
+            }
+        } else if (!nodeConnectorId.equals(other.nodeConnectorId)) {
+            return false;
+        }
+        if (queueId == null) {
+            if (other.queueId != null) {
+                return false;
+            }
+        } else if (!queueId.equals(other.queueId)) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsTracker.java
new file mode 100644 (file)
index 0000000..f187c70
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright IBM Corporation, 2013.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetAllQueuesStatisticsFromAllPortsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetQueueStatisticsFromGivenPortInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.flow.capable.node.connector.queue.statistics.FlowCapableNodeConnectorQueueStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMap;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class QueueStatsTracker extends AbstractListeningStatsTracker<QueueIdAndStatisticsMap, QueueStatsEntry> {
+    private static final Logger logger = LoggerFactory.getLogger(QueueStatsTracker.class);
+    private final OpendaylightQueueStatisticsService queueStatsService;
+
+    QueueStatsTracker(OpendaylightQueueStatisticsService queueStatsService, final FlowCapableContext context, long lifetimeNanos) {
+        super(context, lifetimeNanos);
+        this.queueStatsService = queueStatsService;
+    }
+
+    @Override
+    protected void cleanupSingleStat(DataModificationTransaction trans, QueueStatsEntry item) {
+        InstanceIdentifier<?> queueRef
+                            = getNodeIdentifierBuilder().child(NodeConnector.class, new NodeConnectorKey(item.getNodeConnectorId()))
+                                                .augmentation(FlowCapableNodeConnector.class)
+                                                .child(Queue.class, new QueueKey(item.getQueueId()))
+                                                .augmentation(FlowCapableNodeConnectorQueueStatisticsData.class).build();
+        trans.removeOperationalData(queueRef);
+    }
+
+    @Override
+    protected QueueStatsEntry updateSingleStat(DataModificationTransaction trans, QueueIdAndStatisticsMap item) {
+
+        QueueStatsEntry queueEntry = new QueueStatsEntry(item.getNodeConnectorId(), item.getQueueId());
+
+        FlowCapableNodeConnectorQueueStatisticsDataBuilder queueStatisticsDataBuilder = new FlowCapableNodeConnectorQueueStatisticsDataBuilder();
+
+        FlowCapableNodeConnectorQueueStatisticsBuilder queueStatisticsBuilder = new FlowCapableNodeConnectorQueueStatisticsBuilder();
+
+        queueStatisticsBuilder.fieldsFrom(item);
+
+        queueStatisticsDataBuilder.setFlowCapableNodeConnectorQueueStatistics(queueStatisticsBuilder.build());
+
+        InstanceIdentifier<Queue> queueRef = getNodeIdentifierBuilder().child(NodeConnector.class, new NodeConnectorKey(item.getNodeConnectorId()))
+                                    .augmentation(FlowCapableNodeConnector.class)
+                                    .child(Queue.class, new QueueKey(item.getQueueId())).toInstance();
+
+        QueueBuilder queueBuilder = new QueueBuilder();
+        FlowCapableNodeConnectorQueueStatisticsData qsd = queueStatisticsDataBuilder.build();
+        queueBuilder.addAugmentation(FlowCapableNodeConnectorQueueStatisticsData.class, qsd);
+        queueBuilder.setKey(new QueueKey(item.getQueueId()));
+
+        logger.debug("Augmenting queue statistics {} of queue {} to port {}",
+                                    qsd,
+                                    item.getQueueId(),
+                                    item.getNodeConnectorId());
+
+        trans.putOperationalData(queueRef, queueBuilder.build());
+        return queueEntry;
+    }
+
+    public void request() {
+        if (queueStatsService != null) {
+            GetAllQueuesStatisticsFromAllPortsInputBuilder input = new GetAllQueuesStatisticsFromAllPortsInputBuilder();
+            input.setNode(getNodeRef());
+
+            requestHelper(queueStatsService.getAllQueuesStatisticsFromAllPorts(input.build()));
+        }
+    }
+
+    public void request(NodeConnectorId nodeConnectorId, QueueId queueId) {
+        if (queueStatsService != null) {
+            GetQueueStatisticsFromGivenPortInputBuilder input = new GetQueueStatisticsFromGivenPortInputBuilder();
+
+            input.setNode(getNodeRef());
+            input.setNodeConnectorId(nodeConnectorId);
+            input.setQueueId(queueId);
+
+            requestHelper(queueStatsService.getQueueStatisticsFromGivenPort(input.build()));
+        }
+    }
+
+    @Override
+    public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+        for (Entry<InstanceIdentifier<?>, DataObject> e : change.getCreatedConfigurationData().entrySet()) {
+            if (Queue.class.equals(e.getKey().getTargetType())) {
+                final Queue queue = (Queue) e.getValue();
+                final NodeConnectorKey key = e.getKey().firstKeyOf(NodeConnector.class, NodeConnectorKey.class);
+                logger.debug("Key {} triggered request for connector {} queue {}", key.getId(), queue.getQueueId());
+                request(key.getId(), queue.getQueueId());
+            } else {
+                logger.debug("Ignoring key {}", e.getKey());
+            }
+        }
+
+        final DataModificationTransaction trans = startTransaction();
+        for (InstanceIdentifier<?> key : change.getRemovedConfigurationData()) {
+            if (Queue.class.equals(key.getTargetType())) {
+                @SuppressWarnings("unchecked")
+                final InstanceIdentifier<Queue> queue = (InstanceIdentifier<Queue>)key;
+                final InstanceIdentifier<?> del = InstanceIdentifier.builder(queue)
+                        .augmentation(FlowCapableNodeConnectorQueueStatisticsData.class).build();
+                logger.debug("Key {} triggered remove of augmentation {}", key, del);
+
+                trans.removeOperationalData(del);
+            }
+        }
+        trans.commit();
+    }
+
+    @Override
+    protected InstanceIdentifier<?> listenPath() {
+        return getNodeIdentifierBuilder().child(NodeConnector.class)
+                .augmentation(FlowCapableNodeConnector.class).child(Queue.class).build();
+    }
+
+    @Override
+    protected String statName() {
+        return "Queue";
+    }
+
+    @Override
+    public void start(final DataBrokerService dbs) {
+        if (queueStatsService == null) {
+            logger.debug("No Queue Statistics service, not subscribing to queues on node {}", getNodeIdentifier());
+            return;
+        }
+
+        super.start(dbs);
+    }
+}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/RPCFailedException.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/RPCFailedException.java
new file mode 100644 (file)
index 0000000..308c6dd
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import java.util.Collection;
+
+import org.opendaylight.yangtools.yang.common.RpcError;
+
+final class RPCFailedException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+    private final Collection<RpcError> errors;
+
+    public RPCFailedException(final String message, final Collection<RpcError> errors) {
+        super(message);
+        this.errors = errors;
+    }
+
+    @Override
+    public String toString() {
+        return "RPCFailedException [errors=" + errors + ", message=" + getMessage() + ']';
+    }
+}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsListener.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsListener.java
new file mode 100644 (file)
index 0000000..bd9f96c
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright IBM Corporation, 2013.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.statistics.manager;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsUpdate;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowsStatisticsUpdate;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsUpdate;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupDescStatsUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupFeaturesUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupStatisticsUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterConfigStatsUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterFeaturesUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterStatisticsUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.NodeConnectorStatisticsUpdate;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.QueueStatisticsUpdate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class is responsible for listening for statistics update notifications and
+ * routing them to the appropriate NodeStatisticsHandler.
+
+ * TODO: Need to add error message listener and clean-up the associated tx id
+ * if it exists in the tx-id cache.
+ * @author vishnoianil
+ */
+public class StatisticsListener implements OpendaylightGroupStatisticsListener,
+        OpendaylightMeterStatisticsListener,
+        OpendaylightFlowStatisticsListener,
+        OpendaylightPortStatisticsListener,
+        OpendaylightFlowTableStatisticsListener,
+        OpendaylightQueueStatisticsListener{
+
+    private final static Logger sucLogger = LoggerFactory.getLogger(StatisticsListener.class);
+    private final StatisticsProvider statisticsManager;
+
+    /**
+     * default ctor
+     * @param manager
+     */
+    public StatisticsListener(final StatisticsProvider manager){
+        this.statisticsManager = manager;
+    }
+
+    @Override
+    public void onMeterConfigStatsUpdated(final MeterConfigStatsUpdated notification) {
+        final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId());
+        if (handler != null) {
+            handler.updateMeterConfigStats(notification, notification.isMoreReplies(), notification.getMeterConfigStats());
+        }
+    }
+
+    @Override
+    public void onMeterStatisticsUpdated(MeterStatisticsUpdated notification) {
+        final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId());
+        if (handler != null) {
+            handler.updateMeterStats(notification, notification.isMoreReplies(), notification.getMeterStats());
+        }
+    }
+
+    @Override
+    public void onGroupDescStatsUpdated(GroupDescStatsUpdated notification) {
+        final NodeStatisticsHandler handler = statisticsManager.getStatisticsHandler(notification.getId());
+        if (handler != null) {
+            handler.updateGroupDescStats(notification, notification.isMoreReplies(), notification.getGroupDescStats());
+        }
+    }
+
+    @Override
+    public void onGroupStatisticsUpdated(GroupStatisticsUpdated notification) {
+        final NodeStatisticsHandler handler = statisticsManager.getStatisticsHandler(notification.getId());
+        if (handler != null) {
+            handler.updateGroupStats(notification, notification.isMoreReplies(), notification.getGroupStats());
+        }
+    }
+
+    @Override
+    public void onMeterFeaturesUpdated(MeterFeaturesUpdated notification) {
+        final NodeStatisticsHandler sna = this.statisticsManager.getStatisticsHandler(notification.getId());
+        if (sna != null) {
+            sna.updateMeterFeatures(notification);
+        }
+    }
+
+    @Override
+    public void onGroupFeaturesUpdated(GroupFeaturesUpdated notification) {
+        final NodeStatisticsHandler sna = this.statisticsManager.getStatisticsHandler(notification.getId());
+        if (sna != null) {
+            sna.updateGroupFeatures(notification);
+        }
+    }
+
+    @Override
+    public void onFlowsStatisticsUpdate(final FlowsStatisticsUpdate notification) {
+        sucLogger.debug("Received flow stats update : {}",notification.toString());
+        final NodeStatisticsHandler sna = this.statisticsManager.getStatisticsHandler(notification.getId());
+        if (sna != null) {
+            sna.updateFlowStats(notification, notification.isMoreReplies(), notification.getFlowAndStatisticsMapList());
+        }
+    }
+
+    @Override
+    public void onAggregateFlowStatisticsUpdate(AggregateFlowStatisticsUpdate notification) {
+        final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId());
+        if (handler != null) {
+            handler.updateAggregateFlowStats(notification, notification.isMoreReplies(), notification);
+        }
+    }
+
+    @Override
+    public void onNodeConnectorStatisticsUpdate(NodeConnectorStatisticsUpdate notification) {
+        final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId());
+        if (handler != null) {
+            handler.updateNodeConnectorStats(notification, notification.isMoreReplies(), notification.getNodeConnectorStatisticsAndPortNumberMap());
+        }
+    }
+
+    @Override
+    public void onFlowTableStatisticsUpdate(FlowTableStatisticsUpdate notification) {
+        final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId());
+        if (handler != null) {
+            handler.updateFlowTableStats(notification, notification.isMoreReplies(), notification.getFlowTableAndStatisticsMap());
+        }
+    }
+
+    @Override
+    public void onQueueStatisticsUpdate(QueueStatisticsUpdate notification) {
+        final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId());
+        if (handler != null) {
+            handler.updateQueueStats(notification, notification.isMoreReplies(), notification.getQueueIdAndStatisticsMap());
+        }
+    }
+}
index 653cc8081ab8a953463760560b54cf1bfd197894..5bcbef119a8c332442d405681dd018dc1368c9c7 100644 (file)
@@ -11,37 +11,26 @@ package org.opendaylight.controller.md.statistics.manager;
 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.controller.sal.binding.api.data.DataBrokerService;
 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
 import org.osgi.framework.BundleContext;
 
 public class StatisticsManagerActivator extends AbstractBindingAwareProvider {
+    private StatisticsProvider statsProvider;
 
-    private static ProviderContext pSession;
-    
-    private static StatisticsProvider statsProvider = new StatisticsProvider();
-   
     @Override
     public void onSessionInitiated(ProviderContext session) {
-        
-        pSession = session;
-        DataProviderService dps = session.<DataProviderService>getSALService(DataProviderService.class);
-        StatisticsManagerActivator.statsProvider.setDataService(dps);
-        DataBrokerService dbs = session.<DataBrokerService>getSALService(DataBrokerService.class);
-        StatisticsManagerActivator.statsProvider.setDataBrokerService(dbs);
-        NotificationProviderService nps = session.<NotificationProviderService>getSALService(NotificationProviderService.class);
-        StatisticsManagerActivator.statsProvider.setNotificationService(nps);
-        StatisticsManagerActivator.statsProvider.start();
+        final DataProviderService dps = session.getSALService(DataProviderService.class);
+        final NotificationProviderService nps = session.getSALService(NotificationProviderService.class);
 
+        statsProvider = new StatisticsProvider(dps);
+        statsProvider.start(nps, session);
     }
-    
+
     @Override
     protected void stopImpl(BundleContext context) {
-        StatisticsManagerActivator.statsProvider.close();
-    }
-    
-    public static ProviderContext getProviderContext(){
-        return pSession;
+        if (statsProvider != null) {
+            statsProvider.close();
+            statsProvider = null;
+        }
     }
-
 }
index 325b342cd88bdb71d6d2138169f2f7ae36c83785..892d304daa8d6cd20c7010082f2698cb8de90266 100644 (file)
  */
 package org.opendaylight.controller.md.statistics.manager;
 
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Collection;
+import java.util.Timer;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
 
-import org.eclipse.xtext.xbase.lib.Exceptions;
-import org.opendaylight.controller.md.statistics.manager.MultipartMessageManager.StatsRequestType;
 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
-import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
-import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry;
+import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
-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.table.Flow;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAggregateFlowStatisticsFromFlowTableForAllFlowsOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsFromFlowTableInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsFromFlowTableOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetAllGroupStatisticsInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetAllGroupStatisticsOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetGroupDescriptionInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GetGroupDescriptionOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterConfigStatisticsInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterConfigStatisticsOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterStatisticsInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.GetAllMeterStatisticsOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllNodeConnectorsStatisticsInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllNodeConnectorsStatisticsOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetAllQueuesStatisticsFromAllPortsInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetAllQueuesStatisticsFromAllPortsOutput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetQueueStatisticsFromGivenPortInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.GetQueueStatisticsFromGivenPortOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsService;
+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.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.NotificationListener;
-import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-/** 
+import com.google.common.base.Preconditions;
+
+/**
  * Following are main responsibilities of the class:
- * 1) Invoke statistics request thread to send periodic statistics request to all the 
- * flow capable switch connected to the controller. It sends statistics request for 
- * Group,Meter,Table,Flow,Queue,Aggregate stats.   
- * 
- * 2) Invoke statistics ager thread, to clean up all the stale statistics data from 
+ * 1) Invoke statistics request thread to send periodic statistics request to all the
+ * flow capable switch connected to the controller. It sends statistics request for
+ * Group,Meter,Table,Flow,Queue,Aggregate stats.
+ *
+ * 2) Invoke statistics ager thread, to clean up all the stale statistics data from
  * operational data store.
- * 
+ *
  * @author avishnoi@in.ibm.com
  *
  */
 public class StatisticsProvider implements AutoCloseable {
+    private static final Logger spLogger = LoggerFactory.getLogger(StatisticsProvider.class);
 
-    public final static Logger spLogger = LoggerFactory.getLogger(StatisticsProvider.class);
-    
-    private DataProviderService dps;
-    
-    private DataBrokerService dbs;
+    private final ConcurrentMap<NodeId, NodeStatisticsHandler> handlers = new ConcurrentHashMap<>();
+    private final Timer timer = new Timer("statistics-manager", true);
+    private final DataProviderService dps;
 
-    private NotificationProviderService nps;
-    
     private OpendaylightGroupStatisticsService groupStatsService;
-    
+
     private OpendaylightMeterStatisticsService meterStatsService;
-    
+
     private OpendaylightFlowStatisticsService flowStatsService;
-    
+
     private OpendaylightPortStatisticsService portStatsService;
 
     private OpendaylightFlowTableStatisticsService flowTableStatsService;
 
     private OpendaylightQueueStatisticsService queueStatsService;
 
-    private final MultipartMessageManager multipartMessageManager = new MultipartMessageManager();
-    
-    private StatisticsUpdateHandler statsUpdateHandler;
-    
-    private Thread statisticsRequesterThread;
-    
-    private Thread statisticsAgerThread;
-
-    private final  InstanceIdentifier<Nodes> nodesIdentifier = InstanceIdentifier.builder(Nodes.class).toInstance();
-    
-    public static final int STATS_THREAD_EXECUTION_TIME= 15000;
-    //Local caching of stats
-    
-    private final ConcurrentMap<NodeId,NodeStatisticsAger> statisticsCache = 
-            new ConcurrentHashMap<NodeId,NodeStatisticsAger>();
-    
-    public DataProviderService getDataService() {
-      return this.dps;
-    }
-    
-    public void setDataService(final DataProviderService dataService) {
-      this.dps = dataService;
-    }
-    
-    public DataBrokerService getDataBrokerService() {
-        return this.dbs;
-    }
-      
-    public void setDataBrokerService(final DataBrokerService dataBrokerService) {
-        this.dbs = dataBrokerService;
-    }
-
-    public NotificationProviderService getNotificationService() {
-      return this.nps;
-    }
-    
-    public void setNotificationService(final NotificationProviderService notificationService) {
-      this.nps = notificationService;
+    public StatisticsProvider(final DataProviderService dataService) {
+        this.dps = Preconditions.checkNotNull(dataService);
     }
 
-    public MultipartMessageManager getMultipartMessageManager() {
-        return multipartMessageManager;
-    }
+    private final StatisticsListener updateCommiter = new StatisticsListener(StatisticsProvider.this);
 
-    private final StatisticsUpdateCommiter updateCommiter = new StatisticsUpdateCommiter(StatisticsProvider.this);
-    
     private Registration<NotificationListener> listenerRegistration;
-    
-    public void start() {
-        
-        NotificationProviderService nps = this.getNotificationService();
-        Registration<NotificationListener> registerNotificationListener = nps.registerNotificationListener(this.updateCommiter);
-        this.listenerRegistration = registerNotificationListener;
-        
-        statsUpdateHandler = new StatisticsUpdateHandler(StatisticsProvider.this);
-        
-        registerDataStoreUpdateListener(this.getDataBrokerService());
-        
-        // Get Group/Meter statistics service instance
-        groupStatsService = StatisticsManagerActivator.getProviderContext().
-                getRpcService(OpendaylightGroupStatisticsService.class);
-        
-        meterStatsService = StatisticsManagerActivator.getProviderContext().
-                getRpcService(OpendaylightMeterStatisticsService.class);
-        
-        flowStatsService = StatisticsManagerActivator.getProviderContext().
-                getRpcService(OpendaylightFlowStatisticsService.class);
-
-        portStatsService = StatisticsManagerActivator.getProviderContext().
-                getRpcService(OpendaylightPortStatisticsService.class);
 
-        flowTableStatsService = StatisticsManagerActivator.getProviderContext().
-                getRpcService(OpendaylightFlowTableStatisticsService.class);
-        
-        queueStatsService = StatisticsManagerActivator.getProviderContext().
-                getRpcService(OpendaylightQueueStatisticsService.class);
-        
-        statisticsRequesterThread = new Thread( new Runnable(){
+    private ListenerRegistration<DataChangeListener> flowCapableTrackerRegistration;
 
-            @Override
-            public void run() {
-                while(true){
-                    try {
-                        statsRequestSender();
-                        
-                        Thread.sleep(STATS_THREAD_EXECUTION_TIME);
-                    }catch (Exception e){
-                        spLogger.error("Exception occurred while sending stats request : {}",e);
-                    }
-                }
-            }
-        });
-        
-        spLogger.debug("Statistics requester thread started with timer interval : {}",STATS_THREAD_EXECUTION_TIME);
-        
-        statisticsRequesterThread.start();
-        
-        statisticsAgerThread = new Thread( new Runnable(){
-
-            @Override
-            public void run() {
-                while(true){
-                    try {
-                        for(NodeStatisticsAger nodeStatisticsAger : statisticsCache.values()){
-                            nodeStatisticsAger.cleanStaleStatistics();
-                        }
-                        multipartMessageManager.cleanStaleTransactionIds();
-                        
-                        Thread.sleep(STATS_THREAD_EXECUTION_TIME);
-                    }catch (Exception e){
-                        spLogger.error("Exception occurred while sending stats request : {}",e);
-                    }
-                }
-            }
-        });
-        
-        spLogger.debug("Statistics ager thread started with timer interval : {}",STATS_THREAD_EXECUTION_TIME);
+    public void start(final NotificationProviderService nps, final RpcConsumerRegistry rpcRegistry) {
 
-        statisticsAgerThread.start();
-        
-        spLogger.info("Statistics Provider started.");
-    }
-    
-    private void registerDataStoreUpdateListener(DataBrokerService dbs) {
-        //Register for Node updates
-        InstanceIdentifier<? extends DataObject> pathNode = InstanceIdentifier.builder(Nodes.class)
-                                                                        .child(Node.class).toInstance();
-        dbs.registerDataChangeListener(pathNode, statsUpdateHandler);
+        // Get Group/Meter statistics service instances
+        groupStatsService = rpcRegistry.getRpcService(OpendaylightGroupStatisticsService.class);
+        meterStatsService = rpcRegistry.getRpcService(OpendaylightMeterStatisticsService.class);
+        flowStatsService = rpcRegistry.getRpcService(OpendaylightFlowStatisticsService.class);
+        portStatsService = rpcRegistry.getRpcService(OpendaylightPortStatisticsService.class);
+        flowTableStatsService = rpcRegistry.getRpcService(OpendaylightFlowTableStatisticsService.class);
+        queueStatsService = rpcRegistry.getRpcService(OpendaylightQueueStatisticsService.class);
 
-        //Register for flow updates
-        InstanceIdentifier<? extends DataObject> pathFlow = InstanceIdentifier.builder(Nodes.class).child(Node.class)
-                                                                    .augmentation(FlowCapableNode.class)
-                                                                    .child(Table.class)
-                                                                    .child(Flow.class).toInstance();
-        dbs.registerDataChangeListener(pathFlow, statsUpdateHandler);
-        
-        //Register for meter updates
-        InstanceIdentifier<? extends DataObject> pathMeter = InstanceIdentifier.builder(Nodes.class).child(Node.class)
-                                                    .augmentation(FlowCapableNode.class)
-                                                    .child(Meter.class).toInstance();
+        // Start receiving notifications
+        this.listenerRegistration = nps.registerNotificationListener(this.updateCommiter);
 
-        dbs.registerDataChangeListener(pathMeter, statsUpdateHandler);
-        
-        //Register for group updates 
-        InstanceIdentifier<? extends DataObject> pathGroup = InstanceIdentifier.builder(Nodes.class).child(Node.class)
-                                                    .augmentation(FlowCapableNode.class)
-                                                    .child(Group.class).toInstance();
-        dbs.registerDataChangeListener(pathGroup, statsUpdateHandler);
+        // Register for switch connect/disconnect notifications
+        final InstanceIdentifier<FlowCapableNode> fcnId = InstanceIdentifier.builder(Nodes.class)
+                .child(Node.class).augmentation(FlowCapableNode.class).build();
+        spLogger.debug("Registering FlowCapable tracker to {}", fcnId);
+        this.flowCapableTrackerRegistration = dps.registerDataChangeListener(fcnId,
+                new FlowCapableTracker(this, fcnId));
 
-        //Register for queue updates
-        InstanceIdentifier<? extends DataObject> pathQueue = InstanceIdentifier.builder(Nodes.class).child(Node.class)
-                                                                    .child(NodeConnector.class)
-                                                                    .augmentation(FlowCapableNodeConnector.class)
-                                                                    .child(Queue.class).toInstance();
-        dbs.registerDataChangeListener(pathQueue, statsUpdateHandler);
-    }
-
-    protected DataModificationTransaction startChange() {
-        
-        DataProviderService dps = this.getDataService();
-        return dps.beginTransaction();
+        spLogger.info("Statistics Provider started.");
     }
-    
-    private void statsRequestSender(){
-        
-        List<Node> targetNodes = getAllConnectedNodes();
-        
-        if(targetNodes == null)
-            return;
-        
 
-        for (Node targetNode : targetNodes){
-            
-            if(targetNode.getAugmentation(FlowCapableNode.class) != null){
-                sendStatisticsRequestsToNode(targetNode);
-            }
+    /**
+     * Get the handler for a particular node.
+     *
+     * @param nodeId source node
+     * @return Node statistics handler for that node. Null if the statistics should
+     *         not handled.
+     */
+    public final NodeStatisticsHandler getStatisticsHandler(final NodeId nodeId) {
+        Preconditions.checkNotNull(nodeId);
+        NodeStatisticsHandler handler = handlers.get(nodeId);
+        if (handler == null) {
+            spLogger.info("Attempted to get non-existing handler for {}", nodeId);
         }
+        return handler;
     }
-    
-    public void sendStatisticsRequestsToNode(Node targetNode){
-        
-        spLogger.debug("Send requests for statistics collection to node : {})",targetNode.getId());
-        
-        InstanceIdentifier<Node> targetInstanceId = InstanceIdentifier.builder(Nodes.class).child(Node.class,targetNode.getKey()).toInstance();
-        
-        NodeRef targetNodeRef = new NodeRef(targetInstanceId);
-    
-        try{
-            if(flowStatsService != null){
-                sendAggregateFlowsStatsFromAllTablesRequest(targetNode.getKey());
-                sendAllFlowsStatsFromAllTablesRequest(targetNodeRef);
-            }
-            if(flowTableStatsService != null){
-                sendAllFlowTablesStatisticsRequest(targetNodeRef);
-            }
-            if(portStatsService != null){
-                sendAllNodeConnectorsStatisticsRequest(targetNodeRef);
-            }
-            if(groupStatsService != null){
-                sendAllGroupStatisticsRequest(targetNodeRef);
-                sendGroupDescriptionRequest(targetNodeRef);
-            }
-            if(meterStatsService != null){
-                sendAllMeterStatisticsRequest(targetNodeRef);
-                sendMeterConfigStatisticsRequest(targetNodeRef);
+
+    @Override
+    public void close() {
+        try {
+            if (this.listenerRegistration != null) {
+                this.listenerRegistration.close();
+                this.listenerRegistration = null;
             }
-            if(queueStatsService != null){
-                sendAllQueueStatsFromAllNodeConnector (targetNodeRef);
+            if (this.flowCapableTrackerRegistration != null) {
+                this.flowCapableTrackerRegistration.close();
+                this.flowCapableTrackerRegistration = null;
             }
-        }catch(Exception e){
-            spLogger.error("Exception occured while sending statistics requests : {}", e);
+            timer.cancel();
+        } catch (Exception e) {
+            spLogger.warn("Failed to stop Statistics Provider completely", e);
+        } finally {
+            spLogger.info("Statistics Provider stopped.");
         }
     }
-    
-
-    public void sendAllFlowTablesStatisticsRequest(NodeRef targetNodeRef) throws InterruptedException, ExecutionException {
-        final GetFlowTablesStatisticsInputBuilder input = 
-                new GetFlowTablesStatisticsInputBuilder();
-        
-        input.setNode(targetNodeRef);
-
-        Future<RpcResult<GetFlowTablesStatisticsOutput>> response = 
-                flowTableStatsService.getFlowTablesStatistics(input.build());
-
-        this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNodeRef),response.get().getResult().getTransactionId()
-                , StatsRequestType.ALL_FLOW_TABLE);
-
-    }
 
-    public void sendAllFlowsStatsFromAllTablesRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{
-        final GetAllFlowsStatisticsFromAllFlowTablesInputBuilder input =
-                new GetAllFlowsStatisticsFromAllFlowTablesInputBuilder();
-        
-        input.setNode(targetNode);
-        
-        Future<RpcResult<GetAllFlowsStatisticsFromAllFlowTablesOutput>> response = 
-                flowStatsService.getAllFlowsStatisticsFromAllFlowTables(input.build());
-        
-        this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId()
-                , StatsRequestType.ALL_FLOW);
-        
-    }
-    
-    public void sendFlowStatsFromTableRequest(NodeRef targetNode,Flow flow) throws InterruptedException, ExecutionException{
-        final GetFlowStatisticsFromFlowTableInputBuilder input =
-                new GetFlowStatisticsFromFlowTableInputBuilder();
-        
-        input.setNode(targetNode);
-        input.fieldsFrom(flow);
-        
-        Future<RpcResult<GetFlowStatisticsFromFlowTableOutput>> response = 
-                flowStatsService.getFlowStatisticsFromFlowTable(input.build());
-        
-        this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId()
-                , StatsRequestType.ALL_FLOW);
-        
-    }
-
-    public void sendAggregateFlowsStatsFromAllTablesRequest(NodeKey targetNodeKey) throws InterruptedException, ExecutionException{
-        
-        List<Short> tablesId = getTablesFromNode(targetNodeKey);
-        
-        if(tablesId.size() != 0){
-            for(Short id : tablesId){
-                
-                sendAggregateFlowsStatsFromTableRequest(targetNodeKey,id);
+    void startNodeHandlers(final Collection<NodeKey> addedNodes) {
+        for (NodeKey key : addedNodes) {
+            if (handlers.containsKey(key.getId())) {
+                spLogger.warn("Attempted to start already-existing handler for {}, very strange", key.getId());
+                continue;
             }
-        }else{
-            spLogger.debug("No details found in data store for flow tables associated with Node {}",targetNodeKey);
-        }
-    }
-    
-    public void sendAggregateFlowsStatsFromTableRequest(NodeKey targetNodeKey,Short tableId) throws InterruptedException, ExecutionException{
-        
-        spLogger.debug("Send aggregate stats request for flow table {} to node {}",tableId,targetNodeKey);
-        GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder input = 
-                new GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder();
-                
-        input.setNode(new NodeRef(InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).toInstance()));
-        input.setTableId(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId(tableId));
-        Future<RpcResult<GetAggregateFlowStatisticsFromFlowTableForAllFlowsOutput>> response = 
-                flowStatsService.getAggregateFlowStatisticsFromFlowTableForAllFlows(input.build());
-                
-        multipartMessageManager.setTxIdAndTableIdMapEntry(targetNodeKey.getId(), response.get().getResult().getTransactionId(), tableId);
-        this.multipartMessageManager.addTxIdToRequestTypeEntry(targetNodeKey.getId(), response.get().getResult().getTransactionId()
-                , StatsRequestType.AGGR_FLOW);
-    }
-
-    public void sendAllNodeConnectorsStatisticsRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{
-        
-        final GetAllNodeConnectorsStatisticsInputBuilder input = new GetAllNodeConnectorsStatisticsInputBuilder();
-        
-        input.setNode(targetNode);
-
-        Future<RpcResult<GetAllNodeConnectorsStatisticsOutput>> response = 
-                portStatsService.getAllNodeConnectorsStatistics(input.build());
-        this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId()
-                , StatsRequestType.ALL_PORT);
-
-    }
 
-    public void sendAllGroupStatisticsRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{
-        
-        final GetAllGroupStatisticsInputBuilder input = new GetAllGroupStatisticsInputBuilder();
-        
-        input.setNode(targetNode);
-
-        Future<RpcResult<GetAllGroupStatisticsOutput>> response = 
-                groupStatsService.getAllGroupStatistics(input.build());
-        
-        this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId()
-                , StatsRequestType.ALL_GROUP);
-
-    }
-    
-    public void sendGroupDescriptionRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{
-        final GetGroupDescriptionInputBuilder input = new GetGroupDescriptionInputBuilder();
-        
-        input.setNode(targetNode);
-
-        Future<RpcResult<GetGroupDescriptionOutput>> response = 
-                groupStatsService.getGroupDescription(input.build());
-
-        this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId()
-                , StatsRequestType.GROUP_DESC);
-
-    }
-    
-    public void sendAllMeterStatisticsRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{
-        
-        GetAllMeterStatisticsInputBuilder input = new GetAllMeterStatisticsInputBuilder();
-        
-        input.setNode(targetNode);
-
-        Future<RpcResult<GetAllMeterStatisticsOutput>> response = 
-                meterStatsService.getAllMeterStatistics(input.build());
-        
-        this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId()
-                , StatsRequestType.ALL_METER);;
-
-    }
-    
-    public void sendMeterConfigStatisticsRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{
-        
-        GetAllMeterConfigStatisticsInputBuilder input = new GetAllMeterConfigStatisticsInputBuilder();
-        
-        input.setNode(targetNode);
-
-        Future<RpcResult<GetAllMeterConfigStatisticsOutput>> response = 
-                meterStatsService.getAllMeterConfigStatistics(input.build());
-        
-        this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId()
-                , StatsRequestType.METER_CONFIG);;
-
-    }
-    
-    public void sendAllQueueStatsFromAllNodeConnector(NodeRef targetNode) throws InterruptedException, ExecutionException {
-        GetAllQueuesStatisticsFromAllPortsInputBuilder input = new GetAllQueuesStatisticsFromAllPortsInputBuilder();
-        
-        input.setNode(targetNode);
-        
-        Future<RpcResult<GetAllQueuesStatisticsFromAllPortsOutput>> response = 
-                queueStatsService.getAllQueuesStatisticsFromAllPorts(input.build());
-        
-        this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId()
-                , StatsRequestType.ALL_QUEUE_STATS);;
-
-    }
-
-    public void sendQueueStatsFromGivenNodeConnector(NodeRef targetNode,NodeConnectorId nodeConnectorId, QueueId queueId) throws InterruptedException, ExecutionException {
-        GetQueueStatisticsFromGivenPortInputBuilder input = new GetQueueStatisticsFromGivenPortInputBuilder();
-        
-        input.setNode(targetNode);
-        input.setNodeConnectorId(nodeConnectorId);
-        input.setQueueId(queueId);
-        Future<RpcResult<GetQueueStatisticsFromGivenPortOutput>> response = 
-                queueStatsService.getQueueStatisticsFromGivenPort(input.build());
-        
-        this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId()
-                , StatsRequestType.ALL_QUEUE_STATS);;
-
-    }
-
-    public ConcurrentMap<NodeId, NodeStatisticsAger> getStatisticsCache() {
-        return statisticsCache;
-    }
-    
-    private List<Node> getAllConnectedNodes(){
-        
-        Nodes nodes = (Nodes) dps.readOperationalData(nodesIdentifier);
-        if(nodes == null)
-            return null;
-        
-        spLogger.debug("Number of connected nodes : {}",nodes.getNode().size());
-        return nodes.getNode();
-    }
-    
-    private List<Short> getTablesFromNode(NodeKey nodeKey){
-        InstanceIdentifier<FlowCapableNode> nodesIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class,nodeKey).augmentation(FlowCapableNode.class).toInstance();
-        
-        FlowCapableNode node = (FlowCapableNode)dps.readOperationalData(nodesIdentifier);
-        List<Short> tablesId = new ArrayList<Short>();
-        if(node != null && node.getTable()!=null){
-            spLogger.debug("Number of tables {} supported by node {}",node.getTable().size(),nodeKey);
-            for(Table table: node.getTable()){
-                tablesId.add(table.getId());
+            final NodeStatisticsHandler h = new NodeStatisticsHandler(dps, key,
+                    flowStatsService, flowTableStatsService, groupStatsService,
+                    meterStatsService, portStatsService, queueStatsService);
+            final NodeStatisticsHandler old = handlers.putIfAbsent(key.getId(), h);
+            if (old == null) {
+                spLogger.debug("Started node handler for {}", key.getId());
+                h.start(timer);
+            } else {
+                spLogger.debug("Prevented race on handler for {}", key.getId());
             }
         }
-        return tablesId;
     }
 
-    @SuppressWarnings("unchecked")
-    private NodeId getNodeId(NodeRef nodeRef){
-        InstanceIdentifier<Node> nodeII = (InstanceIdentifier<Node>) nodeRef.getValue();
-        NodeKey nodeKey = InstanceIdentifier.keyOf(nodeII);
-        return nodeKey.getId();
-    }
-    
-    @SuppressWarnings("deprecation")
-    @Override
-    public void close(){
-        
-        try {
-            spLogger.info("Statistics Provider stopped.");
-            if (this.listenerRegistration != null) {
-              
-                this.listenerRegistration.close();
-                
-                this.statisticsRequesterThread.destroy();
-                
-                this.statisticsAgerThread.destroy();
-            
+    void stopNodeHandlers(final Collection<NodeKey> removedNodes) {
+        for (NodeKey key : removedNodes) {
+            final NodeStatisticsHandler s = handlers.remove(key.getId());
+            if (s != null) {
+                spLogger.debug("Stopping node handler for {}", key.getId());
+                s.close();
+            } else {
+                spLogger.warn("Attempted to remove non-existing handler for {}, very strange", key.getId());
             }
-          } catch (Throwable e) {
-            throw Exceptions.sneakyThrow(e);
-          }
+        }
     }
-
 }
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiter.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiter.java
deleted file mode 100644 (file)
index 5f264ab..0000000
+++ /dev/null
@@ -1,959 +0,0 @@
-/*
- * Copyright IBM Corporation, 2013.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.md.statistics.manager;
-
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.List;
-import java.util.concurrent.ConcurrentMap;
-
-import org.opendaylight.controller.md.statistics.manager.NodeStatisticsAger.FlowEntry;
-import org.opendaylight.controller.md.statistics.manager.NodeStatisticsAger.QueueEntry;
-import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey;
-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.statistics.rev130819.AggregateFlowStatisticsData;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsDataBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsUpdate;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsDataBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowsStatisticsUpdate;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsListener;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.aggregate.flow.statistics.AggregateFlowStatisticsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapListBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.statistics.FlowStatisticsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsData;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsDataBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsUpdate;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsListener;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatisticsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupDescStatsUpdated;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupFeaturesUpdated;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupStatisticsUpdated;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStats;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStatsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeatures;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeaturesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatistics;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatisticsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsListener;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.desc.GroupDescBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeaturesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.statistics.GroupStatisticsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterConfigStatsUpdated;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterFeaturesUpdated;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterStatisticsUpdated;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStats;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStatsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeatures;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeaturesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatistics;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatisticsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsListener;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeaturesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterConfigStatsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterStatisticsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsDataBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.NodeConnectorStatisticsUpdate;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsListener;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.flow.capable.node.connector.statistics.FlowCapableNodeConnectorStatisticsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsData;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsDataBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsListener;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.QueueStatisticsUpdate;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.flow.capable.node.connector.queue.statistics.FlowCapableNodeConnectorQueueStatisticsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMap;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Class implement statistics manager related listener interface and augment all the 
- * received statistics data to data stores.
- * TODO: Need to add error message listener and clean-up the associated tx id 
- * if it exists in the tx-id cache.
- * @author vishnoianil
- *
- */
-public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsListener,
-        OpendaylightMeterStatisticsListener, 
-        OpendaylightFlowStatisticsListener,
-        OpendaylightPortStatisticsListener,
-        OpendaylightFlowTableStatisticsListener,
-        OpendaylightQueueStatisticsListener{
-    
-    public final static Logger sucLogger = LoggerFactory.getLogger(StatisticsUpdateCommiter.class);
-
-    private final StatisticsProvider statisticsManager;
-    private final MultipartMessageManager messageManager;
-    
-    private int unaccountedFlowsCounter = 1;
-
-    public StatisticsUpdateCommiter(final StatisticsProvider manager){
-
-        this.statisticsManager = manager;
-        this.messageManager = this.statisticsManager.getMultipartMessageManager();
-    }
-    
-    public StatisticsProvider getStatisticsManager(){
-        return statisticsManager;
-    }
-   
-    @Override
-    public void onMeterConfigStatsUpdated(MeterConfigStatsUpdated notification) {
-        //Check if response is for the request statistics-manager sent.
-        if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
-            return;
-        
-        NodeKey key = new NodeKey(notification.getId());
-
-        //Add statistics to local cache
-        ConcurrentMap<NodeId, NodeStatisticsAger> cache = this.statisticsManager.getStatisticsCache();
-        if(!cache.containsKey(notification.getId())){
-            cache.put(notification.getId(), new NodeStatisticsAger(statisticsManager,key));
-        }
-        cache.get(notification.getId()).updateMeterConfigStats(notification.getMeterConfigStats());
-        
-        //Publish data to configuration data store
-        List<MeterConfigStats> meterConfigStatsList = notification.getMeterConfigStats();
-        
-        for(MeterConfigStats meterConfigStats : meterConfigStatsList){
-            DataModificationTransaction it = this.statisticsManager.startChange();
-            MeterBuilder meterBuilder = new MeterBuilder();
-            MeterKey meterKey = new MeterKey(meterConfigStats.getMeterId());
-            meterBuilder.setKey(meterKey);
-            
-            InstanceIdentifier<Meter> meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key)
-                                                                                        .augmentation(FlowCapableNode.class)
-                                                                                        .child(Meter.class,meterKey).toInstance();
-            
-            NodeMeterConfigStatsBuilder meterConfig= new NodeMeterConfigStatsBuilder();
-            MeterConfigStatsBuilder stats = new MeterConfigStatsBuilder();
-            stats.fieldsFrom(meterConfigStats);
-            meterConfig.setMeterConfigStats(stats.build());
-            
-            //Update augmented data
-            meterBuilder.addAugmentation(NodeMeterConfigStats.class, meterConfig.build());
-            it.putOperationalData(meterRef, meterBuilder.build());
-            it.commit();
-
-        }
-    }
-
-    @Override
-    public void onMeterStatisticsUpdated(MeterStatisticsUpdated notification) {
-        
-        //Check if response is for the request statistics-manager sent.
-        if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
-            return;
-
-        NodeKey key = new NodeKey(notification.getId());
-        
-        List<MeterStats> meterStatsList = notification.getMeterStats();
-        
-        for(MeterStats meterStats : meterStatsList){
-
-            //Publish data to configuration data store
-            DataModificationTransaction it = this.statisticsManager.startChange();
-            MeterBuilder meterBuilder = new MeterBuilder();
-            MeterKey meterKey = new MeterKey(meterStats.getMeterId());
-            meterBuilder.setKey(meterKey);
-            
-            InstanceIdentifier<Meter> meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key)
-                                                                                        .augmentation(FlowCapableNode.class)
-                                                                                        .child(Meter.class,meterKey).toInstance();
-            
-            NodeMeterStatisticsBuilder meterStatsBuilder= new NodeMeterStatisticsBuilder();
-            MeterStatisticsBuilder stats = new MeterStatisticsBuilder();
-            stats.fieldsFrom(meterStats);
-            meterStatsBuilder.setMeterStatistics(stats.build());
-
-            //Update augmented data
-            meterBuilder.addAugmentation(NodeMeterStatistics.class, meterStatsBuilder.build());
-            it.putOperationalData(meterRef, meterBuilder.build());
-            it.commit();
-        }
-    }
-
-    @Override
-    public void onGroupDescStatsUpdated(GroupDescStatsUpdated notification) {
-        
-        //Check if response is for the request statistics-manager sent.
-        if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
-            return;
-
-        NodeKey key = new NodeKey(notification.getId());
-
-        //Add statistics to local cache
-        ConcurrentMap<NodeId, NodeStatisticsAger> cache = this.statisticsManager.getStatisticsCache();
-        if(!cache.containsKey(notification.getId())){
-            cache.put(notification.getId(), new NodeStatisticsAger(statisticsManager,key));
-        }
-        cache.get(notification.getId()).updateGroupDescStats(notification.getGroupDescStats());
-        
-        //Publish data to configuration data store
-        List<GroupDescStats> groupDescStatsList = notification.getGroupDescStats();
-
-        for(GroupDescStats groupDescStats : groupDescStatsList){
-            DataModificationTransaction it = this.statisticsManager.startChange();
-            
-            GroupBuilder groupBuilder = new GroupBuilder();
-            GroupKey groupKey = new GroupKey(groupDescStats.getGroupId());
-            groupBuilder.setKey(groupKey);
-            
-            InstanceIdentifier<Group> groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key)
-                                                                                        .augmentation(FlowCapableNode.class)
-                                                                                        .child(Group.class,groupKey).toInstance();
-
-            NodeGroupDescStatsBuilder groupDesc= new NodeGroupDescStatsBuilder();
-            GroupDescBuilder stats = new GroupDescBuilder();
-            stats.fieldsFrom(groupDescStats);
-            groupDesc.setGroupDesc(stats.build());
-            
-            //Update augmented data
-            groupBuilder.addAugmentation(NodeGroupDescStats.class, groupDesc.build());
-
-            it.putOperationalData(groupRef, groupBuilder.build());
-            it.commit();
-        }
-    }
-
-    @Override
-    public void onGroupStatisticsUpdated(GroupStatisticsUpdated notification) {
-        
-        //Check if response is for the request statistics-manager sent.
-        if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
-            return;
-
-        //Publish data to configuration data store
-        NodeKey key = new NodeKey(notification.getId());
-        List<GroupStats> groupStatsList = notification.getGroupStats();
-
-        for(GroupStats groupStats : groupStatsList){
-            DataModificationTransaction it = this.statisticsManager.startChange();
-            
-            GroupBuilder groupBuilder = new GroupBuilder();
-            GroupKey groupKey = new GroupKey(groupStats.getGroupId());
-            groupBuilder.setKey(groupKey);
-            
-            InstanceIdentifier<Group> groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key)
-                                                                                        .augmentation(FlowCapableNode.class)
-                                                                                        .child(Group.class,groupKey).toInstance();
-
-            NodeGroupStatisticsBuilder groupStatisticsBuilder= new NodeGroupStatisticsBuilder();
-            GroupStatisticsBuilder stats = new GroupStatisticsBuilder();
-            stats.fieldsFrom(groupStats);
-            groupStatisticsBuilder.setGroupStatistics(stats.build());
-            
-            //Update augmented data
-            groupBuilder.addAugmentation(NodeGroupStatistics.class, groupStatisticsBuilder.build());
-            it.putOperationalData(groupRef, groupBuilder.build());
-            it.commit();
-        }
-    }
-    
-    @Override
-    public void onMeterFeaturesUpdated(MeterFeaturesUpdated notification) {
-
-        MeterFeaturesBuilder meterFeature = new MeterFeaturesBuilder();
-        meterFeature.setMeterBandSupported(notification.getMeterBandSupported());
-        meterFeature.setMeterCapabilitiesSupported(notification.getMeterCapabilitiesSupported());
-        meterFeature.setMaxBands(notification.getMaxBands());
-        meterFeature.setMaxColor(notification.getMaxColor());
-        meterFeature.setMaxMeter(notification.getMaxMeter());
-        
-        //Publish data to configuration data store
-        DataModificationTransaction it = this.statisticsManager.startChange();
-        NodeKey key = new NodeKey(notification.getId());
-        NodeRef ref = getNodeRef(key);
-        
-        final NodeBuilder nodeData = new NodeBuilder(); 
-        nodeData.setKey(key);
-        
-        NodeMeterFeaturesBuilder nodeMeterFeatures= new NodeMeterFeaturesBuilder();
-        nodeMeterFeatures.setMeterFeatures(meterFeature.build());
-        
-        //Update augmented data
-        nodeData.addAugmentation(NodeMeterFeatures.class, nodeMeterFeatures.build());
-        
-        InstanceIdentifier<? extends Object> refValue = ref.getValue();
-        it.putOperationalData(refValue, nodeData.build());
-        it.commit();
-    }
-    
-    @Override
-    public void onGroupFeaturesUpdated(GroupFeaturesUpdated notification) {
-
-        GroupFeaturesBuilder groupFeatures = new GroupFeaturesBuilder();
-        groupFeatures.setActions(notification.getActions());
-        groupFeatures.setGroupCapabilitiesSupported(notification.getGroupCapabilitiesSupported());
-        groupFeatures.setGroupTypesSupported(notification.getGroupTypesSupported());
-        groupFeatures.setMaxGroups(notification.getMaxGroups());
-        
-        //Publish data to configuration data store
-        DataModificationTransaction it = this.statisticsManager.startChange();
-        NodeKey key = new NodeKey(notification.getId());
-        NodeRef ref = getNodeRef(key);
-        
-        final NodeBuilder nodeData = new NodeBuilder(); 
-        nodeData.setKey(key);
-        
-        NodeGroupFeaturesBuilder nodeGroupFeatures= new NodeGroupFeaturesBuilder();
-        nodeGroupFeatures.setGroupFeatures(groupFeatures.build());
-        
-        //Update augmented data
-        nodeData.addAugmentation(NodeGroupFeatures.class, nodeGroupFeatures.build());
-        
-        InstanceIdentifier<? extends Object> refValue = ref.getValue();
-        it.putOperationalData(refValue, nodeData.build());
-        it.commit();
-    }
-
-    @Override
-    public void onFlowsStatisticsUpdate(FlowsStatisticsUpdate notification) {
-        
-        //Check if response is for the request statistics-manager sent.
-        if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
-            return;
-
-        NodeKey key = new NodeKey(notification.getId());
-        sucLogger.debug("Received flow stats update : {}",notification.toString());
-        
-        for(FlowAndStatisticsMapList map: notification.getFlowAndStatisticsMapList()){
-            short tableId = map.getTableId();
-            
-            DataModificationTransaction it = this.statisticsManager.startChange();
-
-            boolean foundOriginalFlow = false;
-
-            FlowBuilder flowBuilder = new FlowBuilder();
-
-            FlowStatisticsDataBuilder flowStatisticsData = new FlowStatisticsDataBuilder();
-
-            FlowBuilder flow = new FlowBuilder();
-            flow.setContainerName(map.getContainerName());
-            flow.setBufferId(map.getBufferId());
-            flow.setCookie(map.getCookie());
-            flow.setCookieMask(map.getCookieMask());
-            flow.setFlags(map.getFlags());
-            flow.setFlowName(map.getFlowName());
-            flow.setHardTimeout(map.getHardTimeout());
-            if(map.getFlowId() != null)
-                flow.setId(new FlowId(map.getFlowId().getValue()));
-            flow.setIdleTimeout(map.getIdleTimeout());
-            flow.setInstallHw(map.isInstallHw());
-            flow.setInstructions(map.getInstructions());
-            if(map.getFlowId()!= null)
-                flow.setKey(new FlowKey(new FlowId(map.getKey().getFlowId().getValue())));
-            flow.setMatch(map.getMatch());
-            flow.setOutGroup(map.getOutGroup());
-            flow.setOutPort(map.getOutPort());
-            flow.setPriority(map.getPriority());
-            flow.setStrict(map.isStrict());
-            flow.setTableId(tableId);
-                
-            Flow flowRule = flow.build();
-                
-            FlowAndStatisticsMapListBuilder stats = new FlowAndStatisticsMapListBuilder();
-            stats.setByteCount(map.getByteCount());
-            stats.setPacketCount(map.getPacketCount());
-            stats.setDuration(map.getDuration());
-                
-            GenericStatistics flowStats = stats.build();
-                
-            //Add statistics to local cache
-            ConcurrentMap<NodeId, NodeStatisticsAger> cache = this.statisticsManager.getStatisticsCache();
-            if(!cache.containsKey(notification.getId())){
-                cache.put(notification.getId(), new NodeStatisticsAger(statisticsManager,key));
-            }
-            NodeStatisticsAger nsa = cache.get(notification.getId());
-                
-            //Augment the data to the flow node
-
-            FlowStatisticsBuilder flowStatistics = new FlowStatisticsBuilder();
-            flowStatistics.setByteCount(flowStats.getByteCount());
-            flowStatistics.setPacketCount(flowStats.getPacketCount());
-            flowStatistics.setDuration(flowStats.getDuration());
-            flowStatistics.setContainerName(map.getContainerName());
-            flowStatistics.setBufferId(map.getBufferId());
-            flowStatistics.setCookie(map.getCookie());
-            flowStatistics.setCookieMask(map.getCookieMask());
-            flowStatistics.setFlags(map.getFlags());
-            flowStatistics.setFlowName(map.getFlowName());
-            flowStatistics.setHardTimeout(map.getHardTimeout());
-            flowStatistics.setIdleTimeout(map.getIdleTimeout());
-            flowStatistics.setInstallHw(map.isInstallHw());
-            flowStatistics.setInstructions(map.getInstructions());
-            flowStatistics.setMatch(map.getMatch());
-            flowStatistics.setOutGroup(map.getOutGroup());
-            flowStatistics.setOutPort(map.getOutPort());
-            flowStatistics.setPriority(map.getPriority());
-            flowStatistics.setStrict(map.isStrict());
-            flowStatistics.setTableId(tableId);
-
-            flowStatisticsData.setFlowStatistics(flowStatistics.build());
-                
-            sucLogger.debug("Flow : {}",flowRule.toString());
-            sucLogger.debug("Statistics to augment : {}",flowStatistics.build().toString());
-
-            InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
-                    .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
-            
-            Table table= (Table)it.readConfigurationData(tableRef);
-
-            //TODO: Not a good way to do it, need to figure out better way.
-            //TODO: major issue in any alternate approach is that flow key is incrementally assigned 
-            //to the flows stored in data store.
-            // Augment same statistics to all the matching masked flow
-            if(table != null){
-
-                for(Flow existingFlow : table.getFlow()){
-                    sucLogger.debug("Existing flow in data store : {}",existingFlow.toString());
-                    if(flowEquals(flowRule,existingFlow)){
-                        it = this.statisticsManager.startChange();
-                        InstanceIdentifier<Flow> flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
-                                .augmentation(FlowCapableNode.class)
-                                .child(Table.class, new TableKey(tableId))
-                                .child(Flow.class,existingFlow.getKey()).toInstance();
-                        flowBuilder.setKey(existingFlow.getKey());
-                        flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
-                        sucLogger.debug("Found matching flow in the datastore, augmenting statistics");
-                        foundOriginalFlow = true;
-                        // Update entry with timestamp of latest response 
-                        flow.setKey(existingFlow.getKey());
-                        FlowEntry flowStatsEntry = nsa.new FlowEntry(tableId,flow.build());
-                        cache.get(notification.getId()).updateFlowStats(flowStatsEntry);
-
-                        it.putOperationalData(flowRef, flowBuilder.build());
-                        it.commit();
-                    }
-                }
-            }
-            
-            table= (Table)it.readOperationalData(tableRef);
-            if(!foundOriginalFlow && table != null){
-
-                for(Flow existingFlow : table.getFlow()){
-                    FlowStatisticsData augmentedflowStatisticsData = existingFlow.getAugmentation(FlowStatisticsData.class);
-                    if(augmentedflowStatisticsData != null){
-                        FlowBuilder existingOperationalFlow = new FlowBuilder();
-                        existingOperationalFlow.fieldsFrom(augmentedflowStatisticsData.getFlowStatistics());
-                        sucLogger.debug("Existing unaccounted flow in operational data store : {}",existingFlow.toString());
-                        if(flowEquals(flowRule,existingOperationalFlow.build())){
-                            InstanceIdentifier<Flow> flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
-                                    .augmentation(FlowCapableNode.class)
-                                    .child(Table.class, new TableKey(tableId))
-                                    .child(Flow.class,existingFlow.getKey()).toInstance();
-                            flowBuilder.setKey(existingFlow.getKey());
-                            flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
-                            sucLogger.debug("Found matching unaccounted flow in the operational datastore, augmenting statistics");
-                            foundOriginalFlow = true;
-                            
-                            // Update entry with timestamp of latest response 
-                            flow.setKey(existingFlow.getKey());
-                            FlowEntry flowStatsEntry = nsa.new FlowEntry(tableId,flow.build());
-                            cache.get(notification.getId()).updateFlowStats(flowStatsEntry);
-
-                            it.putOperationalData(flowRef, flowBuilder.build());
-                            it.commit();
-                            break;
-                        }
-                    }
-                }
-            }
-            if(!foundOriginalFlow){
-                String flowKey = "#UF$TABLE*"+Short.toString(tableId)+"*"+Integer.toString(this.unaccountedFlowsCounter);
-                this.unaccountedFlowsCounter++;
-                FlowKey newFlowKey = new FlowKey(new FlowId(flowKey));
-                InstanceIdentifier<Flow> flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
-                        .augmentation(FlowCapableNode.class)
-                        .child(Table.class, new TableKey(tableId))
-                        .child(Flow.class,newFlowKey).toInstance();
-                flowBuilder.setKey(newFlowKey);
-                flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
-                sucLogger.debug("Flow {} is not present in config data store, augmenting statistics as an unaccounted flow",flowBuilder.build());
-                
-                // Update entry with timestamp of latest response 
-                flow.setKey(newFlowKey);
-                FlowEntry flowStatsEntry = nsa.new FlowEntry(tableId,flow.build());
-                cache.get(notification.getId()).updateFlowStats(flowStatsEntry);
-
-                it.putOperationalData(flowRef, flowBuilder.build());
-                it.commit();
-            }
-        }
-    }
-
-    @Override
-    public void onAggregateFlowStatisticsUpdate(AggregateFlowStatisticsUpdate notification) {
-        //Check if response is for the request statistics-manager sent.
-        if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
-            return;
-
-        NodeKey key = new NodeKey(notification.getId());
-        
-        Short tableId = messageManager.getTableIdForTxId(notification.getId(),notification.getTransactionId());
-        if(tableId != null){
-            
-            DataModificationTransaction it = this.statisticsManager.startChange();
-
-            InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
-                    .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
-
-            AggregateFlowStatisticsDataBuilder aggregateFlowStatisticsDataBuilder = new AggregateFlowStatisticsDataBuilder();
-            AggregateFlowStatisticsBuilder aggregateFlowStatisticsBuilder = new AggregateFlowStatisticsBuilder();
-            aggregateFlowStatisticsBuilder.setByteCount(notification.getByteCount());
-            aggregateFlowStatisticsBuilder.setFlowCount(notification.getFlowCount());
-            aggregateFlowStatisticsBuilder.setPacketCount(notification.getPacketCount());
-            aggregateFlowStatisticsDataBuilder.setAggregateFlowStatistics(aggregateFlowStatisticsBuilder.build());
-            
-            sucLogger.debug("Augment aggregate statistics: {} for table {} on Node {}",aggregateFlowStatisticsBuilder.build().toString(),tableId,key);
-
-            TableBuilder tableBuilder = new TableBuilder();
-            tableBuilder.setKey(new TableKey(tableId));
-            tableBuilder.addAugmentation(AggregateFlowStatisticsData.class, aggregateFlowStatisticsDataBuilder.build());
-            it.putOperationalData(tableRef, tableBuilder.build());
-            it.commit();
-
-        }
-    }
-
-    @Override
-    public void onNodeConnectorStatisticsUpdate(NodeConnectorStatisticsUpdate notification) {
-        //Check if response is for the request statistics-manager sent.
-        if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
-            return;
-
-        NodeKey key = new NodeKey(notification.getId());
-        
-        List<NodeConnectorStatisticsAndPortNumberMap> portsStats = notification.getNodeConnectorStatisticsAndPortNumberMap();
-        for(NodeConnectorStatisticsAndPortNumberMap portStats : portsStats){
-            
-            DataModificationTransaction it = this.statisticsManager.startChange();
-
-            FlowCapableNodeConnectorStatisticsBuilder statisticsBuilder 
-                                            = new FlowCapableNodeConnectorStatisticsBuilder();
-            statisticsBuilder.setBytes(portStats.getBytes());
-            statisticsBuilder.setCollisionCount(portStats.getCollisionCount());
-            statisticsBuilder.setDuration(portStats.getDuration());
-            statisticsBuilder.setPackets(portStats.getPackets());
-            statisticsBuilder.setReceiveCrcError(portStats.getReceiveCrcError());
-            statisticsBuilder.setReceiveDrops(portStats.getReceiveDrops());
-            statisticsBuilder.setReceiveErrors(portStats.getReceiveErrors());
-            statisticsBuilder.setReceiveFrameError(portStats.getReceiveFrameError());
-            statisticsBuilder.setReceiveOverRunError(portStats.getReceiveOverRunError());
-            statisticsBuilder.setTransmitDrops(portStats.getTransmitDrops());
-            statisticsBuilder.setTransmitErrors(portStats.getTransmitErrors());
-            
-            //Augment data to the node-connector
-            FlowCapableNodeConnectorStatisticsDataBuilder statisticsDataBuilder = 
-                    new FlowCapableNodeConnectorStatisticsDataBuilder();
-            
-            statisticsDataBuilder.setFlowCapableNodeConnectorStatistics(statisticsBuilder.build());
-            
-            InstanceIdentifier<NodeConnector> nodeConnectorRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key).child(NodeConnector.class, new NodeConnectorKey(portStats.getNodeConnectorId())).toInstance();
-            
-            NodeConnector nodeConnector = (NodeConnector)it.readOperationalData(nodeConnectorRef);
-            
-            if(nodeConnector != null){
-                sucLogger.debug("Augmenting port statistics {} to port {}",statisticsDataBuilder.build().toString(),nodeConnectorRef.toString());
-                NodeConnectorBuilder nodeConnectorBuilder = new NodeConnectorBuilder();
-                nodeConnectorBuilder.addAugmentation(FlowCapableNodeConnectorStatisticsData.class, statisticsDataBuilder.build());
-                it.putOperationalData(nodeConnectorRef, nodeConnectorBuilder.build());
-                it.commit();
-            }
-        }
-    }
-
-    @Override
-    public void onFlowTableStatisticsUpdate(FlowTableStatisticsUpdate notification) {
-        //Check if response is for the request statistics-manager sent.
-        if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
-            return;
-
-        NodeKey key = new NodeKey(notification.getId());
-        
-        List<FlowTableAndStatisticsMap> flowTablesStatsList = notification.getFlowTableAndStatisticsMap();
-        for (FlowTableAndStatisticsMap ftStats : flowTablesStatsList){
-            
-            DataModificationTransaction it = this.statisticsManager.startChange();
-
-            InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
-                    .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(ftStats.getTableId().getValue())).toInstance();
-            
-            FlowTableStatisticsDataBuilder statisticsDataBuilder = new FlowTableStatisticsDataBuilder();
-            
-            FlowTableStatisticsBuilder statisticsBuilder = new FlowTableStatisticsBuilder();
-            statisticsBuilder.setActiveFlows(ftStats.getActiveFlows());
-            statisticsBuilder.setPacketsLookedUp(ftStats.getPacketsLookedUp());
-            statisticsBuilder.setPacketsMatched(ftStats.getPacketsMatched());
-            
-            statisticsDataBuilder.setFlowTableStatistics(statisticsBuilder.build());
-            
-            sucLogger.debug("Augment flow table statistics: {} for table {} on Node {}",statisticsBuilder.build().toString(),ftStats.getTableId(),key);
-            
-            TableBuilder tableBuilder = new TableBuilder();
-            tableBuilder.setKey(new TableKey(ftStats.getTableId().getValue()));
-            tableBuilder.addAugmentation(FlowTableStatisticsData.class, statisticsDataBuilder.build());
-            it.putOperationalData(tableRef, tableBuilder.build());
-            it.commit();
-        }
-    }
-
-    @Override
-    public void onQueueStatisticsUpdate(QueueStatisticsUpdate notification) {
-        
-        //Check if response is for the request statistics-manager sent.
-        if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies()))
-            return;
-
-        NodeKey key = new NodeKey(notification.getId());
-        
-        //Add statistics to local cache
-        ConcurrentMap<NodeId, NodeStatisticsAger> cache = this.statisticsManager.getStatisticsCache();
-        if(!cache.containsKey(notification.getId())){
-            cache.put(notification.getId(), new NodeStatisticsAger(statisticsManager,key));
-        }
-        
-        NodeStatisticsAger nsa = cache.get(notification.getId());
-        
-        List<QueueIdAndStatisticsMap> queuesStats = notification.getQueueIdAndStatisticsMap();
-        for(QueueIdAndStatisticsMap swQueueStats : queuesStats){
-            
-            QueueEntry queueEntry = nsa.new QueueEntry(swQueueStats.getNodeConnectorId(),swQueueStats.getQueueId());
-            nsa.updateQueueStats(queueEntry);
-            
-            FlowCapableNodeConnectorQueueStatisticsDataBuilder queueStatisticsDataBuilder = new FlowCapableNodeConnectorQueueStatisticsDataBuilder();
-            
-            FlowCapableNodeConnectorQueueStatisticsBuilder queueStatisticsBuilder = new FlowCapableNodeConnectorQueueStatisticsBuilder();
-            
-            queueStatisticsBuilder.fieldsFrom(swQueueStats);
-            
-            queueStatisticsDataBuilder.setFlowCapableNodeConnectorQueueStatistics(queueStatisticsBuilder.build());
-            
-            DataModificationTransaction it = this.statisticsManager.startChange();
-
-            InstanceIdentifier<Queue> queueRef 
-                    = InstanceIdentifier.builder(Nodes.class)
-                                        .child(Node.class, key)
-                                        .child(NodeConnector.class, new NodeConnectorKey(swQueueStats.getNodeConnectorId()))
-                                        .augmentation(FlowCapableNodeConnector.class)
-                                        .child(Queue.class, new QueueKey(swQueueStats.getQueueId())).toInstance();
-            
-            QueueBuilder queueBuilder = new QueueBuilder();
-            queueBuilder.addAugmentation(FlowCapableNodeConnectorQueueStatisticsData.class, queueStatisticsDataBuilder.build());
-            queueBuilder.setKey(new QueueKey(swQueueStats.getQueueId()));
-
-            sucLogger.debug("Augmenting queue statistics {} of queue {} to port {}"
-                                        ,queueStatisticsDataBuilder.build().toString(),
-                                        swQueueStats.getQueueId(),
-                                        swQueueStats.getNodeConnectorId());
-            
-            it.putOperationalData(queueRef, queueBuilder.build());
-            it.commit();
-            
-        }
-        
-    }
-
-    private NodeRef getNodeRef(NodeKey nodeKey){
-        InstanceIdentifierBuilder<?> builder = InstanceIdentifier.builder(Nodes.class).child(Node.class, nodeKey);
-        return new NodeRef(builder.toInstance());
-    }
-   
-    public boolean flowEquals(Flow statsFlow, Flow storedFlow) {
-        if (statsFlow.getClass() != storedFlow.getClass()) {
-            return false;
-        }
-        if (statsFlow.getContainerName()== null) {
-            if (storedFlow.getContainerName()!= null) {
-                return false;
-            }
-        } else if(!statsFlow.getContainerName().equals(storedFlow.getContainerName())) {
-            return false;
-        }
-        if (statsFlow.getMatch()== null) {
-            if (storedFlow.getMatch() != null) {
-                return false;
-            }
-        } //else if(!statsFlow.getMatch().equals(storedFlow.getMatch())) {
-        else if(!matchEquals(statsFlow.getMatch(), storedFlow.getMatch())) {
-            return false;
-        }
-        if (storedFlow.getPriority() == null) {
-            if (statsFlow.getPriority() != null && statsFlow.getPriority()!= 0x8000) {
-                return false;
-            }
-        } else if(!statsFlow.getPriority().equals(storedFlow.getPriority())) {
-            return false;
-        }
-        if (statsFlow.getTableId() == null) {
-            if (storedFlow.getTableId() != null) {
-                return false;
-            }
-        } else if(!statsFlow.getTableId().equals(storedFlow.getTableId())) {
-            return false;
-        }
-        return true;
-    }
-    
-    /**
-     * Explicit equals method to compare the 'match' for flows stored in the data-stores and flow fetched from the switch.
-     * Flow installation process has three steps 
-     * 1) Store flow in config data store 
-     * 2) and send it to plugin for installation
-     * 3) Flow gets installed in switch
-     * 
-     * The flow user wants to install and what finally gets installed in switch can be slightly different. 
-     * E.g, If user installs flow with src/dst ip=10.0.0.1/24, when it get installed in the switch
-     * src/dst ip will be changes to 10.0.0.0/24 because of netmask of 24. When statistics manager fetch 
-     * stats it gets 10.0.0.0/24 rather then 10.0.0.1/24. Custom match takes care of by using masked ip
-     * while comparing two ip addresses.
-     * 
-     * Sometimes when user don't provide few values that is required by flow installation request, like 
-     * priority,hard timeout, idle timeout, cookies etc, plugin usages default values before sending 
-     * request to the switch. So when statistics manager gets flow statistics, it gets the default value.
-     * But the flow stored in config data store don't have those defaults value. I included those checks 
-     * in the customer flow/match equal function. 
-     * 
-     * 
-     * @param statsFlow
-     * @param storedFlow
-     * @return
-     */
-    
-    public boolean matchEquals(Match statsFlow, Match storedFlow) {
-        if (statsFlow == storedFlow) {
-            return true;
-        }
-        if (storedFlow.getClass() != statsFlow.getClass()) {
-            return false;
-        }
-        if (storedFlow.getEthernetMatch() == null) {
-            if (statsFlow.getEthernetMatch() != null) {
-                return false;
-            }
-        } else if(!storedFlow.getEthernetMatch().equals(statsFlow.getEthernetMatch())) {
-            return false;
-        }
-        if (storedFlow.getIcmpv4Match()== null) {
-            if (statsFlow.getIcmpv4Match() != null) {
-                return false;
-            }
-        } else if(!storedFlow.getIcmpv4Match().equals(statsFlow.getIcmpv4Match())) {
-            return false;
-        }
-        if (storedFlow.getIcmpv6Match() == null) {
-            if (statsFlow.getIcmpv6Match() != null) {
-                return false;
-            }
-        } else if(!storedFlow.getIcmpv6Match().equals(statsFlow.getIcmpv6Match())) {
-            return false;
-        }
-        if (storedFlow.getInPhyPort() == null) {
-            if (statsFlow.getInPhyPort() != null) {
-                return false;
-            }
-        } else if(!storedFlow.getInPhyPort().equals(statsFlow.getInPhyPort())) {
-            return false;
-        }
-        if (storedFlow.getInPort()== null) {
-            if (statsFlow.getInPort() != null) {
-                return false;
-            }
-        } else if(!storedFlow.getInPort().equals(statsFlow.getInPort())) {
-            return false;
-        }
-        if (storedFlow.getIpMatch()== null) {
-            if (statsFlow.getIpMatch() != null) {
-                return false;
-            }
-        } else if(!storedFlow.getIpMatch().equals(statsFlow.getIpMatch())) {
-            return false;
-        }
-        if (storedFlow.getLayer3Match()== null) {
-            if (statsFlow.getLayer3Match() != null) {
-                    return false;
-            }
-        } else if(!layer3MatchEquals(statsFlow.getLayer3Match(),storedFlow.getLayer3Match())) {
-            return false;
-        }
-        if (storedFlow.getLayer4Match()== null) {
-            if (statsFlow.getLayer4Match() != null) {
-                return false;
-            }
-        } else if(!storedFlow.getLayer4Match().equals(statsFlow.getLayer4Match())) {
-            return false;
-        }
-        if (storedFlow.getMetadata() == null) {
-            if (statsFlow.getMetadata() != null) {
-                return false;
-            }
-        } else if(!storedFlow.getMetadata().equals(statsFlow.getMetadata())) {
-            return false;
-        }
-        if (storedFlow.getProtocolMatchFields() == null) {
-            if (statsFlow.getProtocolMatchFields() != null) {
-                return false;
-            }
-        } else if(!storedFlow.getProtocolMatchFields().equals(statsFlow.getProtocolMatchFields())) {
-            return false;
-        }
-        if (storedFlow.getTunnel()== null) {
-            if (statsFlow.getTunnel() != null) {
-                return false;
-            }
-        } else if(!storedFlow.getTunnel().equals(statsFlow.getTunnel())) {
-            return false;
-        }
-        if (storedFlow.getVlanMatch()== null) {
-            if (statsFlow.getVlanMatch() != null) {
-                return false;
-            }
-        } else if(!storedFlow.getVlanMatch().equals(statsFlow.getVlanMatch())) {
-            return false;
-        }
-        return true;
-    }
-
-    private boolean layer3MatchEquals(Layer3Match statsLayer3Match, Layer3Match storedLayer3Match){
-
-        if(statsLayer3Match instanceof Ipv4Match && storedLayer3Match instanceof Ipv4Match){
-            Ipv4Match statsIpv4Match = (Ipv4Match)statsLayer3Match;
-            Ipv4Match storedIpv4Match = (Ipv4Match)storedLayer3Match;
-            
-            if (storedIpv4Match.getIpv4Destination()== null) {
-                if (statsIpv4Match.getIpv4Destination()!= null) {
-                    return false;
-                }
-            } else if(!IpAddressEquals(statsIpv4Match.getIpv4Destination(),storedIpv4Match.getIpv4Destination())){
-                return false;
-            }
-            if (storedIpv4Match.getIpv4Source() == null) {
-                if (statsIpv4Match.getIpv4Source() != null) {
-                    return false;
-                }
-            } else if(!IpAddressEquals(statsIpv4Match.getIpv4Source(),storedIpv4Match.getIpv4Source())) {
-                return false;
-            }
-            
-            return true;
-        }else{
-            return storedLayer3Match.equals(statsLayer3Match);
-        }
-    }
-    
-    private boolean IpAddressEquals(Ipv4Prefix statsIpAddress, Ipv4Prefix storedIpAddress) {
-        IntegerIpAddress statsIpAddressInt = StrIpToIntIp(statsIpAddress.getValue());
-        IntegerIpAddress storedIpAddressInt = StrIpToIntIp(storedIpAddress.getValue());
-
-        if(IpAndMaskBasedMatch(statsIpAddressInt,storedIpAddressInt)){
-            return true;
-        }
-        if(IpBasedMatch(statsIpAddressInt,storedIpAddressInt)){
-            return true;
-        }
-        return false;
-    }
-
-    private boolean IpAndMaskBasedMatch(IntegerIpAddress statsIpAddressInt,IntegerIpAddress storedIpAddressInt){
-        return ((statsIpAddressInt.getIp() & statsIpAddressInt.getMask()) ==  (storedIpAddressInt.getIp() & storedIpAddressInt.getMask()));
-    }
-
-    private boolean IpBasedMatch(IntegerIpAddress statsIpAddressInt,IntegerIpAddress storedIpAddressInt){
-        return (statsIpAddressInt.getIp() == storedIpAddressInt.getIp());
-    }
-    
-    /*
-     * Method return integer version of ip address. Converted int will be mask if 
-     * mask specified
-     */
-    private IntegerIpAddress StrIpToIntIp(String ipAddresss){
-        
-        String[] parts = ipAddresss.split("/");
-        String ip = parts[0];
-        int prefix;
-
-        if (parts.length < 2) {
-            prefix = 32;
-        } else {
-            prefix = Integer.parseInt(parts[1]);
-        }
-
-        Inet4Address addr =null;
-        try {
-            addr = (Inet4Address) InetAddress.getByName(ip);
-        } catch (UnknownHostException e){}
-
-        byte[] addrBytes = addr.getAddress();
-        int ipInt = ((addrBytes[0] & 0xFF) << 24) |
-                         ((addrBytes[1] & 0xFF) << 16) |
-                         ((addrBytes[2] & 0xFF) << 8)  |
-                         ((addrBytes[3] & 0xFF) << 0);
-
-        int mask = 0xffffffff << 32 - prefix;
-
-        return new IntegerIpAddress(ipInt, mask);
-    }
-    
-    class IntegerIpAddress{
-        int ip;
-        int mask;
-        public IntegerIpAddress(int ip, int mask) {
-            this.ip = ip;
-            this.mask = mask;
-        }
-        public int getIp() {
-            return ip;
-        }
-        public int getMask() {
-            return mask;
-        }
-    }
-}
-
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateHandler.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateHandler.java
deleted file mode 100644 (file)
index 941a8f8..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright IBM Corporation, 2013.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.md.statistics.manager;
-
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-
-import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
-import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
-import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStats;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatistics;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStats;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatistics;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsData;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Following are two main responsibilities of the class
- * 1) Listen for the create changes in config data store for tree nodes (Flow,Group,Meter,Queue) 
- * and send statistics request to the switch to fetch the statistics
- * 
- * 2)Listen for the remove changes in config data store for tree nodes (Flow,Group,Meter,Queue)
- * and remove the relative statistics data from operational data store.
- * 
- * @author avishnoi@in.ibm.com
- *
- */
-public class StatisticsUpdateHandler implements DataChangeListener {
-
-    public final static Logger suhLogger = LoggerFactory.getLogger(StatisticsUpdateHandler.class);
-
-    private final StatisticsProvider statisticsManager;
-    
-    public StatisticsUpdateHandler(final StatisticsProvider manager){
-
-        this.statisticsManager = manager;
-    }
-    
-    public StatisticsProvider getStatisticsManager(){
-        return statisticsManager;
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
-        
-        Map<InstanceIdentifier<?>, DataObject> nodeAdditions = change.getCreatedOperationalData();
-        for (InstanceIdentifier<? extends DataObject> dataObjectInstance : nodeAdditions.keySet()) {
-            DataObject dataObject = nodeAdditions.get(dataObjectInstance);
-            if(dataObject instanceof Node){
-                
-                Node node = (Node) dataObject;
-                if(node.getAugmentation(FlowCapableNode.class) != null){
-                    this.statisticsManager.sendStatisticsRequestsToNode(node);
-                }
-            }
-        }
-
-        Map<InstanceIdentifier<?>, DataObject> additions = change.getCreatedConfigurationData();
-        for (InstanceIdentifier<? extends DataObject> dataObjectInstance : additions.keySet()) {
-            DataObject dataObject = additions.get(dataObjectInstance);
-            InstanceIdentifier<Node> nodeII = dataObjectInstance.firstIdentifierOf(Node.class);
-            NodeRef nodeRef = new NodeRef(nodeII);
-            if(dataObject instanceof Flow){
-                Flow flow = (Flow) dataObject;
-                try {
-                    this.statisticsManager.sendFlowStatsFromTableRequest(nodeRef, flow);
-                } catch (InterruptedException | ExecutionException e) {
-                    suhLogger.warn("Following exception occured while sending flow statistics request newly added flow: {}", e);
-                }
-            }
-            if(dataObject instanceof Meter){
-                try {
-                    this.statisticsManager.sendMeterConfigStatisticsRequest(nodeRef);
-                } catch (InterruptedException | ExecutionException e) {
-                    suhLogger.warn("Following exception occured while sending meter statistics request for newly added meter: {}", e);
-                }
-            }
-            if(dataObject instanceof Group){
-                try {
-                    this.statisticsManager.sendGroupDescriptionRequest(nodeRef);
-                } catch (InterruptedException | ExecutionException e) {
-                    suhLogger.warn("Following exception occured while sending group description request for newly added group: {}", e);
-                }
-            }
-            if(dataObject instanceof Queue){
-                Queue queue = (Queue) dataObject;
-                InstanceIdentifier<NodeConnector> nodeConnectorII = dataObjectInstance.firstIdentifierOf(NodeConnector.class);
-                NodeConnectorKey nodeConnectorKey = InstanceIdentifier.keyOf(nodeConnectorII);
-                try {
-                    this.statisticsManager.sendQueueStatsFromGivenNodeConnector(nodeRef, nodeConnectorKey.getId(), queue.getQueueId());
-                } catch (InterruptedException | ExecutionException e) {
-                    suhLogger.warn("Following exception occured while sending queue statistics request for newly added group: {}", e);
-                }
-            }
-        }
-            
-        Set<InstanceIdentifier<? extends DataObject>> removals = change.getRemovedConfigurationData();
-        for (InstanceIdentifier<? extends DataObject> dataObjectInstance : removals) {
-            DataObject dataObject = change.getOriginalConfigurationData().get(dataObjectInstance);
-            
-            if(dataObject instanceof Flow){
-                InstanceIdentifier<Flow> flowII = (InstanceIdentifier<Flow>)dataObjectInstance;
-                InstanceIdentifier<?> flowAugmentation = 
-                        InstanceIdentifier.builder(flowII).augmentation(FlowStatisticsData.class).toInstance();
-                removeAugmentedOperationalData(flowAugmentation);
-            }
-            if(dataObject instanceof Meter){
-                InstanceIdentifier<Meter> meterII = (InstanceIdentifier<Meter>)dataObjectInstance;
-                
-                InstanceIdentifier<?> nodeMeterConfigStatsAugmentation = 
-                        InstanceIdentifier.builder(meterII).augmentation(NodeMeterConfigStats.class).toInstance();
-                removeAugmentedOperationalData(nodeMeterConfigStatsAugmentation);
-
-                InstanceIdentifier<?> nodeMeterStatisticsAugmentation = 
-                        InstanceIdentifier.builder(meterII).augmentation(NodeMeterStatistics.class).toInstance();
-                removeAugmentedOperationalData(nodeMeterStatisticsAugmentation);
-            }
-            
-            if(dataObject instanceof Group){
-                InstanceIdentifier<Group> groupII = (InstanceIdentifier<Group>)dataObjectInstance;
-                
-                InstanceIdentifier<?> nodeGroupDescStatsAugmentation = 
-                        InstanceIdentifier.builder(groupII).augmentation(NodeGroupDescStats.class).toInstance();
-                removeAugmentedOperationalData(nodeGroupDescStatsAugmentation);
-
-                InstanceIdentifier<?> nodeGroupStatisticsAugmentation = 
-                        InstanceIdentifier.builder(groupII).augmentation(NodeGroupStatistics.class).toInstance();
-                removeAugmentedOperationalData(nodeGroupStatisticsAugmentation);
-            }
-            
-            if(dataObject instanceof Queue){
-                InstanceIdentifier<Queue> queueII = (InstanceIdentifier<Queue>)dataObjectInstance;
-                
-                InstanceIdentifier<?> nodeConnectorQueueStatisticsDataAugmentation = 
-                        InstanceIdentifier.builder(queueII).augmentation(FlowCapableNodeConnectorQueueStatisticsData.class).toInstance();
-                removeAugmentedOperationalData(nodeConnectorQueueStatisticsDataAugmentation);
-            }
-        }
-    }
-    
-    private void removeAugmentedOperationalData(InstanceIdentifier<? extends DataObject> dataObjectInstance ){
-        if(dataObjectInstance != null){
-            DataModificationTransaction it = this.statisticsManager.startChange();
-            it.removeOperationalData(dataObjectInstance);
-            it.commit();
-        }
-    }
-}
diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiterTest.java b/opendaylight/md-sal/statistics-manager/src/test/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiterTest.java
new file mode 100644 (file)
index 0000000..bf523a4
--- /dev/null
@@ -0,0 +1,115 @@
+/**
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.md.statistics.manager;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ */
+public class StatisticsUpdateCommiterTest {
+
+    private static final Logger LOG = LoggerFactory
+            .getLogger(StatisticsUpdateCommiterTest.class);
+
+    /**
+     * Test method for {@link org.opendaylight.controller.md.statistics.manager.StatisticsListener#layer3MatchEquals(org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match, org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match)}.
+     */
+    @Test
+    public void testLayer3MatchEquals() {
+        String[][][] matchSeeds = new String[][][] {
+                {{"10.1.2.0/24", "10.1.2.0/24"}, {"10.1.2.0/24", "10.1.2.0/24"}},
+                {{"10.1.2.0/24", "10.1.2.0/24"}, {"10.1.2.0/24", "10.1.1.0/24"}},
+                {{"10.1.1.0/24", "10.1.2.0/24"}, {"10.1.2.0/24", "10.1.2.0/24"}},
+                {{"10.1.1.0/24", "10.1.1.0/24"}, {"10.1.2.0/24", "10.1.2.0/24"}},
+
+                {{"10.1.1.0/24", null}, {"10.1.1.0/24", "10.1.2.0/24"}},
+                {{"10.1.1.0/24", null}, {"10.1.2.0/24", "10.1.2.0/24"}},
+                {{"10.1.1.0/24", null}, {"10.1.2.0/24", null}},
+                {{"10.1.1.0/24", null}, {"10.1.1.0/24", null}},
+
+                {{null, "10.1.1.0/24"}, {"10.1.2.0/24", "10.1.1.0/24"}},
+                {{null, "10.1.1.0/24"}, {"10.1.2.0/24", "10.1.2.0/24"}},
+                {{null, "10.1.1.0/24"}, {null, "10.1.2.0/24"}},
+                {{null, "10.1.1.0/24"}, {null, "10.1.1.0/24"}},
+
+                {{null, null}, {null, "10.1.1.0/24"}},
+                {{null, null}, {null, null}},
+        };
+
+        boolean[] matches = new boolean[] {
+                true,
+                false,
+                false,
+                false,
+
+                false,
+                false,
+                false,
+                true,
+
+                false,
+                false,
+                false,
+                true,
+
+                false,
+                true
+        };
+
+        for (int i = 0; i < matches.length; i++) {
+            checkComparisonOfL3Match(
+                    matchSeeds[i][0][0], matchSeeds[i][0][1],
+                    matchSeeds[i][1][0], matchSeeds[i][1][1],
+                    matches[i]);
+        }
+    }
+
+    /**
+     * @param m1Source match1 - src
+     * @param m1Destination match1 - dest
+     * @param m2Source match2 - src
+     * @param msDestination match2 - dest
+     * @param matches expected match output
+     *
+     */
+    private static void checkComparisonOfL3Match(String m1Source, String m1Destination,
+            String m2Source, String msDestination, boolean matches) {
+        Ipv4Match m1Layer3 = prepareIPv4Match(m1Source, m1Destination);
+        Ipv4Match m2Layer3 = prepareIPv4Match(m2Source, msDestination);
+        boolean comparisonResult;
+        try {
+            comparisonResult = FlowComparator.layer3MatchEquals(m1Layer3, m2Layer3);
+            Assert.assertEquals("failed to compare: "+m1Layer3+" vs. "+m2Layer3,
+                    matches, comparisonResult);
+        } catch (Exception e) {
+            LOG.error("failed to compare: {} vs. {}", m1Layer3, m2Layer3, e);
+            Assert.fail(e.getMessage());
+        }
+    }
+
+    private static Ipv4Match prepareIPv4Match(String source, String destination) {
+        Ipv4MatchBuilder ipv4MatchBuilder = new Ipv4MatchBuilder();
+        if (source != null) {
+            ipv4MatchBuilder.setIpv4Source(new Ipv4Prefix(source));
+        }
+        if (destination != null) {
+            ipv4MatchBuilder.setIpv4Destination(new Ipv4Prefix(destination));
+        }
+
+        return ipv4MatchBuilder.build();
+    }
+
+}
diff --git a/opendaylight/md-sal/statistics-manager/src/test/resources/log4j-test.xml b/opendaylight/md-sal/statistics-manager/src/test/resources/log4j-test.xml
new file mode 100644 (file)
index 0000000..bd3bf3c
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">\r
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">\r
+\r
+    <appender name="console" class="org.apache.log4j.ConsoleAppender">\r
+        <layout class="org.apache.log4j.PatternLayout">\r
+            <param name="ConversionPattern" value="%-6p %d{HH:mm:ss.SSS} [%10.10t] %30.30c %x - %m%n" />\r
+        </layout>\r
+    </appender>\r
+\r
+    <logger name="org.opendaylight.controller.md.statistics" additivity="false">\r
+        <level value="DEBUG" />\r
+        <appender-ref ref="console" />\r
+    </logger>\r
+\r
+    <root>\r
+        <priority value="INFO" />\r
+        <appender-ref ref="console" />\r
+    </root>\r
+</log4j:configuration>\r
index 502d58122082c8a9f60df8d5626c8d37f5374f3f..54d24a4cec3823c0a07e1bfaf5e36b2c69815d0d 100644 (file)
@@ -8,6 +8,11 @@
 
 package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes;
 
+import javax.management.openmbean.ArrayType;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
@@ -16,11 +21,6 @@ import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDepende
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
 
-import javax.management.openmbean.ArrayType;
-import javax.management.openmbean.CompositeType;
-import javax.management.openmbean.OpenType;
-import javax.management.openmbean.SimpleType;
-
 public abstract class AttributeIfcSwitchStatement<T> {
 
     protected AttributeIfc lastAttribute;
@@ -102,6 +102,8 @@ public abstract class AttributeIfcSwitchStatement<T> {
     protected abstract T caseListDependeciesAttribute(ArrayType<?> openType);
 
     private static class UnknownOpenTypeException extends RuntimeException {
+        private static final long serialVersionUID = 1L;
+
         public UnknownOpenTypeException(String message) {
             super(message);
         }
index 01d872d89cad71156b792b37dc2e78f1749f393a..460aec6ac6fa94b4977c433ba3f6e76805bc8e8e 100644 (file)
@@ -8,16 +8,27 @@
 
 package org.opendaylight.controller.netconf.persist.impl;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import io.netty.channel.EventLoopGroup;
+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 org.opendaylight.controller.config.api.ConflictingVersionException;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 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.NetconfUtil;
-import org.opendaylight.controller.netconf.util.messages.NetconfMessageAdditionalHeader;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
 import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
@@ -27,20 +38,12 @@ import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.xml.sax.SAXException;
 
-import javax.annotation.concurrent.Immutable;
-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.TimeUnit;
+import com.google.common.base.Preconditions;
+import io.netty.channel.EventLoopGroup;
 
 @Immutable
 public class ConfigPusher {
-    private static final Logger logger = LoggerFactory.getLogger(ConfigPersisterNotificationHandler.class);
+    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;
 
@@ -59,7 +62,7 @@ public class ConfigPusher {
     }
 
     public ConfigPusher(InetSocketAddress address, EventLoopGroup nettyThreadGroup,
-                        long maxWaitForCapabilitiesMillis, long connectionTimeoutMillis) {
+            long maxWaitForCapabilitiesMillis, long connectionTimeoutMillis) {
         this.address = address;
         this.nettyThreadGroup = nettyThreadGroup;
         this.maxWaitForCapabilitiesMillis = maxWaitForCapabilitiesMillis;
@@ -129,8 +132,8 @@ public class ConfigPusher {
         final long deadlineNanos = pollingStartNanos + TimeUnit.MILLISECONDS.toNanos(maxWaitForCapabilitiesMillis);
         int attempt = 0;
 
-        String additionalHeader = NetconfMessageAdditionalHeader.toString("unknown", address.getAddress().getHostAddress(),
-                Integer.toString(address.getPort()), "tcp", Optional.of("persister"));
+        NetconfHelloMessageAdditionalHeader additionalHeader = new NetconfHelloMessageAdditionalHeader("unknown", address.getAddress().getHostAddress(),
+                Integer.toString(address.getPort()), "tcp", "persister");
 
         Set<String> latestCapabilities = null;
         while (System.nanoTime() < deadlineNanos) {
@@ -224,13 +227,12 @@ public class ConfigPusher {
             NetconfMessage netconfMessage = netconfClient.sendMessage(request, NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY);
             NetconfUtil.checkIsMessageOk(netconfMessage);
             return netconfMessage;
-        } catch (RuntimeException e) { // TODO: change NetconfClient#sendMessage to throw checked exceptions
+        } catch (RuntimeException | ExecutionException | InterruptedException | TimeoutException e) {
             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";
@@ -316,4 +318,4 @@ public class ConfigPusher {
                     '}';
         }
     }
-}
\ No newline at end of file
+}
diff --git a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/AbstractNetconfSession.java b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/AbstractNetconfSession.java
new file mode 100644 (file)
index 0000000..bd75c27
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * 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.api;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
+
+import java.io.IOException;
+
+import org.opendaylight.protocol.framework.AbstractProtocolSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class AbstractNetconfSession<S extends NetconfSession, L extends NetconfSessionListener<S>> extends AbstractProtocolSession<NetconfMessage> implements NetconfSession {
+    private static final Logger logger = LoggerFactory.getLogger(AbstractNetconfSession.class);
+    private final L sessionListener;
+    private final long sessionId;
+    private boolean up = false;
+
+    protected final Channel channel;
+
+    protected AbstractNetconfSession(L sessionListener, Channel channel, long sessionId) {
+        this.sessionListener = sessionListener;
+        this.channel = channel;
+        this.sessionId = sessionId;
+        logger.debug("Session {} created", toString());
+    }
+
+    protected abstract S thisInstance();
+
+    @Override
+    public void close() {
+        channel.close();
+        up = false;
+        sessionListener.onSessionTerminated(thisInstance(), new NetconfTerminationReason("Session closed"));
+    }
+
+    @Override
+    protected void handleMessage(NetconfMessage netconfMessage) {
+        logger.debug("handling incoming message");
+        sessionListener.onMessage(thisInstance(), netconfMessage);
+    }
+
+    @Override
+    public ChannelFuture sendMessage(NetconfMessage netconfMessage) {
+        return channel.writeAndFlush(netconfMessage);
+    }
+
+    @Override
+    protected void endOfInput() {
+        logger.debug("Session {} end of input detected while session was in state {}", toString(), isUp() ? "up"
+                : "initialized");
+        if (isUp()) {
+            this.sessionListener.onSessionDown(thisInstance(), new IOException("End of input detected. Close the session."));
+        }
+    }
+
+    @Override
+    protected void sessionUp() {
+        logger.debug("Session {} up", toString());
+        sessionListener.onSessionUp(thisInstance());
+        this.up = true;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuffer sb = new StringBuffer("ServerNetconfSession{");
+        sb.append("sessionId=").append(sessionId);
+        sb.append('}');
+        return sb.toString();
+    }
+
+    public final boolean isUp() {
+        return up;
+    }
+
+    public final long getSessionId() {
+        return sessionId;
+    }
+}
+
index f42db6938de7e6a6c2b7048271e7ce65840b0c82..6e27b48978549e95fecb9dd84663ff9a74e8154e 100644 (file)
@@ -8,14 +8,12 @@
 
 package org.opendaylight.controller.netconf.api;
 
-import org.opendaylight.protocol.framework.DeserializerException;
-
 /**
  * This exception is thrown by
  * {@link NetconfSessionListener#onMessage(NetconfMessage)} to indicate fatal
  * communication problem after which the session should be closed.
  */
-public class NetconfDeserializerException extends DeserializerException {
+public class NetconfDeserializerException extends Exception {
     private static final long serialVersionUID = 1L;
 
     public NetconfDeserializerException(final String message) {
index 1107572df1bda55be26504399697b7327f68636c..5a85e9425783c4171ce41d52b01dd71b9a3c9079 100644 (file)
@@ -11,13 +11,11 @@ package org.opendaylight.controller.netconf.api;
 import java.util.Collections;
 import java.util.Map;
 
-import org.opendaylight.protocol.framework.DocumentedException;
-
 /**
  * Checked exception to communicate an error that needs to be sent to the
  * netconf client.
  */
-public class NetconfDocumentedException extends DocumentedException {
+public class NetconfDocumentedException extends Exception {
 
     private static final long serialVersionUID = 1L;
 
index 7877843ccb99c7ad91230467720b7bbf17f72e25..78586a3fec2bb926690771732769dc71ddaff99d 100644 (file)
@@ -10,34 +10,18 @@ package org.opendaylight.controller.netconf.api;
 
 import org.w3c.dom.Document;
 
-import com.google.common.base.Optional;
-
 /**
  * NetconfMessage represents a wrapper around org.w3c.dom.Document. Needed for
  * implementing ProtocolMessage interface.
  */
-public final class NetconfMessage {
-
-    private static final long serialVersionUID = 462175939836367285L;
-
+public class NetconfMessage {
     private final Document doc;
 
-    private String additionalHeader;
-
     public NetconfMessage(final Document doc) {
-        this(doc, null);
-    }
-
-    public NetconfMessage(Document doc, String additionalHeader) {
         this.doc = doc;
-        this.additionalHeader = additionalHeader;
     }
 
     public Document getDocument() {
         return this.doc;
     }
-
-    public Optional<String> getAdditionalHeader() {
-        return additionalHeader== null ? Optional.<String>absent() : Optional.of(additionalHeader);
-    }
 }
index 6c747dbe244fde8812a17a8f923eff49c67fba4d..e52e71ceea91ac43f470c110d1127c499b748b42 100644 (file)
@@ -7,74 +7,10 @@
  */
 package org.opendaylight.controller.netconf.api;
 
-import io.netty.channel.Channel;
-import org.opendaylight.protocol.framework.AbstractProtocolSession;
-import org.opendaylight.protocol.framework.SessionListener;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import io.netty.channel.ChannelFuture;
 
-import java.io.IOException;
+import org.opendaylight.protocol.framework.ProtocolSession;
 
-public abstract class NetconfSession extends AbstractProtocolSession<NetconfMessage> {
-    protected final Channel channel;
-    private final SessionListener sessionListener;
-    private final long sessionId;
-    private boolean up = false;
-    private static final Logger logger = LoggerFactory.getLogger(NetconfSession.class);
-
-    protected NetconfSession(SessionListener sessionListener, Channel channel, long sessionId) {
-        this.sessionListener = sessionListener;
-        this.channel = channel;
-        this.sessionId = sessionId;
-        logger.debug("Session {} created", toString());
-    }
-    @Override
-    public void close() {
-        channel.close();
-        up = false;
-        sessionListener.onSessionTerminated(this, new NetconfTerminationReason("Session closed"));
-    }
-
-    @Override
-    protected void handleMessage(NetconfMessage netconfMessage) {
-        logger.debug("handling incoming message");
-        sessionListener.onMessage(this, netconfMessage);
-    }
-
-    public void sendMessage(NetconfMessage netconfMessage) {
-        channel.writeAndFlush(netconfMessage);
-    }
-
-    @Override
-    protected void endOfInput() {
-        logger.debug("Session {} end of input detected while session was in state {}", toString(), isUp() ? "up"
-                : "initialized");
-        if (isUp()) {
-            this.sessionListener.onSessionDown(this, new IOException("End of input detected. Close the session."));
-        }
-    }
-
-    @Override
-    protected void sessionUp() {
-        logger.debug("Session {} up", toString());
-        sessionListener.onSessionUp(this);
-        this.up = true;
-    }
-
-    @Override
-    public String toString() {
-        final StringBuffer sb = new StringBuffer("ServerNetconfSession{");
-        sb.append("sessionId=").append(sessionId);
-        sb.append('}');
-        return sb.toString();
-    }
-
-    public boolean isUp() {
-        return up;
-    }
-
-    public long getSessionId() {
-        return sessionId;
-    }
+public interface NetconfSession extends ProtocolSession<NetconfMessage> {
+    ChannelFuture sendMessage(NetconfMessage message);
 }
-
index 54cb471604d6fc5114f5d3b5e1dbe1c273fa4f01..0f7869d97a80047731f27a48cf7e241df618fd1b 100644 (file)
@@ -10,7 +10,6 @@ package org.opendaylight.controller.netconf.api;
 
 import org.opendaylight.protocol.framework.SessionListener;
 
-public interface NetconfSessionListener extends
-        SessionListener<NetconfMessage, NetconfSession, NetconfTerminationReason> {
+public interface NetconfSessionListener<S extends NetconfSession> extends SessionListener<NetconfMessage, S, NetconfTerminationReason> {
 
 }
index 48109d1353ec6eae5d301342de409e4205c312ec..6ae966d1f71b7299ce3b7f444df179a6bbcc4e2a 100644 (file)
@@ -15,7 +15,7 @@ import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 /**
  * Class extending {@link NetconfClientSessionListener} to provide notification capability.
  */
-public abstract class AbstractNetconfClientNotifySessionListener extends NetconfClientSessionListener {
+public abstract class AbstractNetconfClientNotifySessionListener extends SimpleNetconfClientSessionListener {
     /*
      * Maybe some capabilities could be expressed as internal NetconfClientSessionListener handlers.
      * It would enable NetconfClient functionality to be extended by using namespace handlers.
@@ -31,7 +31,7 @@ public abstract class AbstractNetconfClientNotifySessionListener extends Netconf
      * @param message {@see NetconfClientSessionListener#onMessage(NetconfClientSession, NetconfMessage)}
      */
     @Override
-    public final synchronized void onMessage(NetconfClientSession session, NetconfMessage message) {
+    public final void onMessage(NetconfClientSession session, NetconfMessage message) {
         if (isNotification(message)) {
             onNotification(session, message);
         } else {
index 4fcad2cbd6afef217f32d23f71383f13f277414c..4cdca208bc5e472088b07741b958c2e716e3f2dd 100644 (file)
@@ -8,17 +8,8 @@
 
 package org.opendaylight.controller.netconf.client;
 
-import com.google.common.base.Preconditions;
-import com.google.common.base.Stopwatch;
-import com.google.common.collect.Sets;
 import io.netty.util.concurrent.Future;
 import io.netty.util.concurrent.GlobalEventExecutor;
-import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.protocol.framework.NeverReconnectStrategy;
-import org.opendaylight.protocol.framework.ReconnectStrategy;
-import org.opendaylight.protocol.framework.TimedReconnectStrategy;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.io.Closeable;
 import java.io.IOException;
@@ -27,7 +18,23 @@ import java.util.Set;
 import java.util.concurrent.CancellationException;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.protocol.framework.NeverReconnectStrategy;
+import org.opendaylight.protocol.framework.ReconnectStrategy;
+import org.opendaylight.protocol.framework.TimedReconnectStrategy;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Stopwatch;
+import com.google.common.collect.Sets;
+
+/**
+ * @deprecated Use {@link NetconfClientDispatcher.createClient()} or {@link NetconfClientDispatcher.createReconnectingClient()} instead.
+ */
+@Deprecated
 public class NetconfClient implements Closeable {
 
     private static final Logger logger = LoggerFactory.getLogger(NetconfClient.class);
@@ -50,7 +57,7 @@ public class NetconfClient implements Closeable {
     private NetconfClient(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strat, NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
         this.label = clientLabelForLogging;
         dispatch = netconfClientDispatcher;
-        sessionListener = new NetconfClientSessionListener();
+        sessionListener = new SimpleNetconfClientSessionListener();
         Future<NetconfClientSession> clientFuture = dispatch.createClient(address, sessionListener, strat);
         this.address = address;
         clientSession = get(clientFuture);
@@ -61,18 +68,19 @@ public class NetconfClient implements Closeable {
         try {
             return clientFuture.get();
         } catch (CancellationException e) {
-            throw new RuntimeException("Netconf client interrupted", e);
+            throw new RuntimeException("Cancelling " + this, e);
         } catch (ExecutionException e) {
-            throw new IllegalStateException("Unable to create netconf client", e);
+            throw new IllegalStateException("Unable to create " + this, e);
         }
     }
 
-    public static NetconfClient clientFor(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strat, NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
-        return new NetconfClient(clientLabelForLogging,address,strat,netconfClientDispatcher);
+    public static NetconfClient clientFor(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strategy, NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
+        return new NetconfClient(clientLabelForLogging,address,strategy,netconfClientDispatcher);
     }
 
-    public static NetconfClient clientFor(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strat, NetconfClientDispatcher netconfClientDispatcher,NetconfClientSessionListener listener) throws InterruptedException {
-        return new NetconfClient(clientLabelForLogging,address,strat,netconfClientDispatcher,listener);
+    public static NetconfClient clientFor(String clientLabelForLogging, InetSocketAddress address,
+            ReconnectStrategy strategy, NetconfClientDispatcher netconfClientDispatcher, NetconfClientSessionListener listener) throws InterruptedException {
+        return new NetconfClient(clientLabelForLogging,address,strategy,netconfClientDispatcher,listener);
     }
 
     public NetconfClient(String clientLabelForLogging, InetSocketAddress address, int connectTimeoutMs,
@@ -87,36 +95,42 @@ public class NetconfClient implements Closeable {
                 DEFAULT_CONNECT_TIMEOUT), netconfClientDispatcher);
     }
 
-    public NetconfClient(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strat,
+    public NetconfClient(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strategy,
             NetconfClientDispatcher netconfClientDispatcher, NetconfClientSessionListener listener) throws InterruptedException{
         this.label = clientLabelForLogging;
         dispatch = netconfClientDispatcher;
         sessionListener = listener;
-        Future<NetconfClientSession> clientFuture = dispatch.createClient(address, sessionListener, strat);
+        Future<NetconfClientSession> clientFuture = dispatch.createClient(address, sessionListener, strategy);
         this.address = address;
         clientSession = get(clientFuture);
         this.sessionId = clientSession.getSessionId();
     }
 
-    public NetconfMessage sendMessage(NetconfMessage message) {
+    public Future<NetconfMessage> sendRequest(NetconfMessage message) {
+        return ((SimpleNetconfClientSessionListener)sessionListener).sendRequest(message);
+    }
+
+    /**
+     * @deprecated Use {@link sendRequest} instead
+     */
+    @Deprecated
+    public NetconfMessage sendMessage(NetconfMessage message) throws ExecutionException, InterruptedException, TimeoutException {
         return sendMessage(message, 5, 1000);
     }
 
-    public NetconfMessage sendMessage(NetconfMessage message, int attempts, int attemptMsDelay) {
-        Stopwatch stopwatch = new Stopwatch().start();
-        Preconditions.checkState(clientSession.isUp(), "Session was not up yet");
+    /**
+     * @deprecated Use {@link sendRequest} instead
+     */
+    @Deprecated
+    public NetconfMessage sendMessage(NetconfMessage message, int attempts, int attemptMsDelay) throws ExecutionException, InterruptedException, TimeoutException {
         //logger.debug("Sending message: {}",XmlUtil.toString(message.getDocument()));
-        clientSession.sendMessage(message);
+        final Stopwatch stopwatch = new Stopwatch().start();
+
         try {
-            return sessionListener.getLastMessage(attempts, attemptMsDelay);
-        } catch (InterruptedException e) {
-            Thread.currentThread().interrupt();
-            throw new RuntimeException(this + " Cannot read message from " + address, e);
-        } catch (IllegalStateException e) {
-            throw new IllegalStateException(this + " Cannot read message from " + address, e);
+            return sendRequest(message).get(attempts * attemptMsDelay, TimeUnit.MILLISECONDS);
         } finally {
             stopwatch.stop();
-            logger.debug("Total time spent waiting for response {} ms", stopwatch.elapsed(TimeUnit.MILLISECONDS));
+            logger.debug("Total time spent waiting for response from {}: {} ms", address, stopwatch.elapsed(TimeUnit.MILLISECONDS));
         }
     }
 
index 1228a84a8a71a07fb1be4438407c5c8e8e4af54f..43664b3233b7fdca0787016089cc90a6f1b60553 100644 (file)
@@ -8,43 +8,47 @@
 
 package org.opendaylight.controller.netconf.client;
 
-import com.google.common.base.Optional;
 import io.netty.channel.EventLoopGroup;
 import io.netty.channel.socket.SocketChannel;
 import io.netty.util.HashedWheelTimer;
 import io.netty.util.concurrent.Future;
 import io.netty.util.concurrent.Promise;
-import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.api.NetconfSession;
-import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
+
+import java.io.Closeable;
+import java.net.InetSocketAddress;
+
 import org.opendaylight.controller.netconf.util.AbstractChannelInitializer;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
 import org.opendaylight.protocol.framework.AbstractDispatcher;
 import org.opendaylight.protocol.framework.ReconnectStrategy;
-import org.opendaylight.protocol.framework.SessionListener;
+import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
 import org.opendaylight.protocol.framework.SessionListenerFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.Closeable;
-import java.net.InetSocketAddress;
+import com.google.common.base.Optional;
 
 public class NetconfClientDispatcher extends AbstractDispatcher<NetconfClientSession, NetconfClientSessionListener> implements Closeable {
 
-    private static final Logger logger = LoggerFactory.getLogger(NetconfClient.class);
+    private static final Logger logger = LoggerFactory.getLogger(NetconfClientDispatcher.class);
 
-    private final NetconfClientSessionNegotiatorFactory negotatorFactory;
+    private final NetconfClientSessionNegotiatorFactory negotiatorFactory;
     private final HashedWheelTimer timer;
 
-    public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup, long clientConnectionTimeoutMillis) {
+    public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup,
+            long clientConnectionTimeoutMillis) {
         super(bossGroup, workerGroup);
         timer = new HashedWheelTimer();
-        this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.<String>absent(), clientConnectionTimeoutMillis);
+        this.negotiatorFactory = new NetconfClientSessionNegotiatorFactory(timer,
+                Optional.<NetconfHelloMessageAdditionalHeader> absent(), clientConnectionTimeoutMillis);
     }
 
-    public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup, String additionalHeader, long connectionTimeoutMillis) {
+    public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup,
+            NetconfHelloMessageAdditionalHeader additionalHeader, long connectionTimeoutMillis) {
         super(bossGroup, workerGroup);
         timer = new HashedWheelTimer();
-        this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader), connectionTimeoutMillis);
+        this.negotiatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader),
+                connectionTimeoutMillis);
     }
 
     public Future<NetconfClientSession> createClient(InetSocketAddress address,
@@ -58,38 +62,54 @@ public class NetconfClientDispatcher extends AbstractDispatcher<NetconfClientSes
             }
 
             private void initialize(SocketChannel ch, Promise<NetconfClientSession> promise) {
-                new ClientChannelInitializer( negotatorFactory, sessionListener).initialize(ch, promise);
+                new ClientChannelInitializer(negotiatorFactory, sessionListener).initialize(ch, promise);
             }
         });
     }
 
-    private static class ClientChannelInitializer extends AbstractChannelInitializer {
+    public Future<Void> createReconnectingClient(final InetSocketAddress address,
+            final NetconfClientSessionListener listener,
+            final ReconnectStrategyFactory connectStrategyFactory, final ReconnectStrategy reestablishStrategy) {
+        final ClientChannelInitializer init = new ClientChannelInitializer(negotiatorFactory, listener);
+
+        return super.createReconnectingClient(address, connectStrategyFactory, reestablishStrategy,
+                new PipelineInitializer<NetconfClientSession>() {
+            @Override
+            public void initializeChannel(final SocketChannel ch, final Promise<NetconfClientSession> promise) {
+                init.initialize(ch, promise);
+            }
+        });
+    }
+
+    private static class ClientChannelInitializer extends AbstractChannelInitializer<NetconfClientSession> {
 
         private final NetconfClientSessionNegotiatorFactory negotiatorFactory;
         private final NetconfClientSessionListener sessionListener;
 
         private ClientChannelInitializer(NetconfClientSessionNegotiatorFactory negotiatorFactory,
-                                            NetconfClientSessionListener sessionListener) {
+                NetconfClientSessionListener sessionListener) {
             this.negotiatorFactory = negotiatorFactory;
             this.sessionListener = sessionListener;
         }
 
         @Override
-        public void initialize(SocketChannel ch, Promise<? extends NetconfSession> promise) {
+        public void initialize(SocketChannel ch, Promise<NetconfClientSession> promise) {
                 super.initialize(ch,promise);
         }
 
         @Override
-        protected void initializeAfterDecoder(SocketChannel ch, Promise<? extends NetconfSession> promise) {
-            ch.pipeline().addLast("negotiator", negotiatorFactory.getSessionNegotiator(new SessionListenerFactory() {
-                @Override
-                public SessionListener<NetconfMessage, NetconfClientSession, NetconfTerminationReason> getSessionListener() {
-                    return sessionListener;
-                }
-            }, ch, promise));
+        protected void initializeSessionNegotiator(SocketChannel ch, Promise<NetconfClientSession> promise) {
+            ch.pipeline().addAfter(NETCONF_MESSAGE_DECODER,  AbstractChannelInitializer.NETCONF_SESSION_NEGOTIATOR,
+                    negotiatorFactory.getSessionNegotiator(
+                            new SessionListenerFactory<NetconfClientSessionListener>() {
+                                @Override
+                                public NetconfClientSessionListener getSessionListener() {
+                                    return sessionListener;
+                                }
+                            }, ch, promise));
         }
-
     }
+
     @Override
     public void close() {
         try {
index c57487f70b8d12779d88b68c7e20fe879739790a..2d07dd58332ea6bd8b5c030a6408be876aae0278 100644 (file)
@@ -9,19 +9,19 @@
 package org.opendaylight.controller.netconf.client;
 
 import io.netty.channel.Channel;
-import org.opendaylight.controller.netconf.api.NetconfSession;
-import org.opendaylight.protocol.framework.SessionListener;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.util.Collection;
 
-public class NetconfClientSession extends NetconfSession {
+import org.opendaylight.controller.netconf.api.AbstractNetconfSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class NetconfClientSession extends AbstractNetconfSession<NetconfClientSession, NetconfClientSessionListener> {
 
     private static final Logger logger = LoggerFactory.getLogger(NetconfClientSession.class);
     private final Collection<String> capabilities;
 
-    public NetconfClientSession(SessionListener sessionListener, Channel channel, long sessionId,
+    public NetconfClientSession(NetconfClientSessionListener sessionListener, Channel channel, long sessionId,
             Collection<String> capabilities) {
         super(sessionListener,channel,sessionId);
         this.capabilities = capabilities;
@@ -32,4 +32,8 @@ public class NetconfClientSession extends NetconfSession {
         return capabilities;
     }
 
+    @Override
+    protected NetconfClientSession thisInstance() {
+        return this;
+    }
 }
index d3c1b22c845a9c0a30888cbd933e935322cfedd8..21be3a8cabf4cf24edb6a9fc08530ebce76bcb53 100644 (file)
@@ -1,75 +1,14 @@
 /*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
-
 package org.opendaylight.controller.netconf.client;
 
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
-import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
-import org.opendaylight.protocol.framework.SessionListener;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-public class NetconfClientSessionListener implements
-        SessionListener<NetconfMessage, NetconfClientSession, NetconfTerminationReason> {
-
-    private static final Logger logger = LoggerFactory.getLogger(NetconfClientSessionListener.class);
-    private AtomicBoolean up = new AtomicBoolean(false);
-
-    @Override
-    public void onSessionUp(NetconfClientSession clientSession) {
-        up.set(true);
-    }
-
-    @Override
-    public void onSessionDown(NetconfClientSession clientSession, Exception e) {
-        logger.debug("Client Session {} down, reason: {}", clientSession, e.getMessage());
-        up.set(false);
-    }
-
-    @Override
-    public void onSessionTerminated(NetconfClientSession clientSession,
-            NetconfTerminationReason netconfTerminationReason) {
-        logger.debug("Client Session {} terminated, reason: {}", clientSession,
-                netconfTerminationReason.getErrorMessage());
-        up.set(false);
-    }
-
-    @Override
-    public synchronized void onMessage(NetconfClientSession session, NetconfMessage message) {
-        synchronized (messages) {
-            this.messages.add(message);
-        }
-    }
-
-    private int lastReadMessage = -1;
-    private List<NetconfMessage> messages = Lists.newArrayList();
-
-    public NetconfMessage getLastMessage(int attempts, int attemptMsDelay) throws InterruptedException {
-        Preconditions.checkState(up.get(), "Session was not up yet");
-
-        for (int i = 0; i < attempts; i++) {
-            synchronized (messages) {
-                if (messages.size() - 1 > lastReadMessage) {
-                    lastReadMessage++;
-                    return messages.get(lastReadMessage);
-                }
-            }
+import org.opendaylight.controller.netconf.api.NetconfSessionListener;
 
-            if (up.get() == false)
-                throw new IllegalStateException("Session ended while trying to read message");
-            Thread.sleep(attemptMsDelay);
-        }
+public interface NetconfClientSessionListener extends NetconfSessionListener<NetconfClientSession> {
 
-        throw new IllegalStateException("No netconf message to read");
-    }
 }
index 100b98c15af18e1791dc4c43fcc460189ee4384e..c742bafe5e2ab52e371d9ebe1b9ca33696734849 100644 (file)
@@ -8,33 +8,35 @@
 
 package org.opendaylight.controller.netconf.client;
 
-import com.google.common.base.Function;
-import com.google.common.collect.Collections2;
-import io.netty.channel.Channel;
-import io.netty.util.Timer;
-import io.netty.util.concurrent.Promise;
-import org.opendaylight.controller.netconf.api.NetconfMessage;
+import java.util.Collection;
+import java.util.List;
+
+import javax.annotation.Nullable;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+
 import org.opendaylight.controller.netconf.api.NetconfSessionPreferences;
 import org.opendaylight.controller.netconf.util.AbstractNetconfSessionNegotiator;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
 import org.opendaylight.controller.netconf.util.xml.XMLNetconfUtil;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
 import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-import org.opendaylight.protocol.framework.SessionListener;
 import org.w3c.dom.Document;
 import org.w3c.dom.Node;
 
-import javax.annotation.Nullable;
-import javax.xml.xpath.XPathConstants;
-import javax.xml.xpath.XPathExpression;
-import java.util.Collection;
-import java.util.List;
+import com.google.common.base.Function;
+import com.google.common.collect.Collections2;
+
+import io.netty.channel.Channel;
+import io.netty.util.Timer;
+import io.netty.util.concurrent.Promise;
 
 public class NetconfClientSessionNegotiator extends
-        AbstractNetconfSessionNegotiator<NetconfSessionPreferences, NetconfClientSession> {
+        AbstractNetconfSessionNegotiator<NetconfSessionPreferences, NetconfClientSession, NetconfClientSessionListener> {
 
     protected NetconfClientSessionNegotiator(NetconfSessionPreferences sessionPreferences,
-            Promise<NetconfClientSession> promise, Channel channel, Timer timer, SessionListener sessionListener,
+            Promise<NetconfClientSession> promise, Channel channel, Timer timer, NetconfClientSessionListener sessionListener,
             long connectionTimeoutMillis) {
         super(sessionPreferences, promise, channel, timer, sessionListener, connectionTimeoutMillis);
     }
@@ -69,7 +71,7 @@ public class NetconfClientSessionNegotiator extends
     }
 
     @Override
-    protected NetconfClientSession getSession(SessionListener sessionListener, Channel channel, NetconfMessage message) {
+    protected NetconfClientSession getSession(NetconfClientSessionListener sessionListener, Channel channel, NetconfHelloMessage message) {
         return new NetconfClientSession(sessionListener, channel, extractSessionId(message.getDocument()),
                 getCapabilities(message.getDocument()));
     }
index db6c024e5afe24e35d336ce2c5322340814289eb..bb372b3affc3e379bbff702805d7db6cca2b6b7f 100644 (file)
@@ -8,31 +8,34 @@
 
 package org.opendaylight.controller.netconf.client;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
 import io.netty.channel.Channel;
 import io.netty.util.Timer;
 import io.netty.util.concurrent.Promise;
+
+import java.io.IOException;
+import java.io.InputStream;
+
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.NetconfSessionPreferences;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.opendaylight.protocol.framework.SessionListenerFactory;
 import org.opendaylight.protocol.framework.SessionNegotiator;
 import org.opendaylight.protocol.framework.SessionNegotiatorFactory;
 import org.xml.sax.SAXException;
 
-import java.io.IOException;
-import java.io.InputStream;
-
-public class NetconfClientSessionNegotiatorFactory implements SessionNegotiatorFactory {
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
 
-    private final Timer timer;
+public class NetconfClientSessionNegotiatorFactory implements SessionNegotiatorFactory<NetconfMessage, NetconfClientSession, NetconfClientSessionListener> {
 
-    private final Optional<String> additionalHeader;
+    private final Optional<NetconfHelloMessageAdditionalHeader> additionalHeader;
     private final long connectionTimeoutMillis;
+    private final Timer timer;
 
-    public NetconfClientSessionNegotiatorFactory(Timer timer, Optional<String> additionalHeader, long connectionTimeoutMillis) {
-        this.timer = timer;
+    public NetconfClientSessionNegotiatorFactory(Timer timer, Optional<NetconfHelloMessageAdditionalHeader> additionalHeader, long connectionTimeoutMillis) {
+        this.timer = Preconditions.checkNotNull(timer);
         this.additionalHeader = additionalHeader;
         this.connectionTimeoutMillis = connectionTimeoutMillis;
     }
@@ -48,16 +51,18 @@ public class NetconfClientSessionNegotiatorFactory implements SessionNegotiatorF
     }
 
     @Override
-    public SessionNegotiator getSessionNegotiator(SessionListenerFactory sessionListenerFactory, Channel channel,
-            Promise promise) {
+    public SessionNegotiator<NetconfClientSession> getSessionNegotiator(SessionListenerFactory<NetconfClientSessionListener> sessionListenerFactory, Channel channel,
+            Promise<NetconfClientSession> promise) {
         // Hello message needs to be recreated every time
         NetconfMessage helloMessage = loadHelloMessageTemplate();
+
         if(this.additionalHeader.isPresent()) {
-            helloMessage = new NetconfMessage(helloMessage.getDocument(), additionalHeader.get());
-        }
+            helloMessage = new NetconfHelloMessage(helloMessage.getDocument(), additionalHeader.get());
+        } else
+            helloMessage = new NetconfHelloMessage(helloMessage.getDocument());
+
         NetconfSessionPreferences proposal = new NetconfSessionPreferences(helloMessage);
         return new NetconfClientSessionNegotiator(proposal, promise, channel, timer,
                 sessionListenerFactory.getSessionListener(), connectionTimeoutMillis);
     }
-
 }
index 06239b2bfd4ef000345229c6c12c5791429751d0..5b82ff22156341b8543b59d3c95bd72e6d9b77cd 100644 (file)
@@ -8,68 +8,80 @@
 
 package org.opendaylight.controller.netconf.client;
 
-import com.google.common.base.Optional;
-import io.netty.channel.ChannelHandler;
 import io.netty.channel.EventLoopGroup;
 import io.netty.channel.socket.SocketChannel;
 import io.netty.util.HashedWheelTimer;
 import io.netty.util.concurrent.Future;
 import io.netty.util.concurrent.Promise;
-import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.api.NetconfSession;
-import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+
 import org.opendaylight.controller.netconf.util.AbstractChannelInitializer;
 import org.opendaylight.controller.netconf.util.handler.ssh.SshHandler;
 import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler;
 import org.opendaylight.controller.netconf.util.handler.ssh.client.Invoker;
-import org.opendaylight.controller.netconf.util.messages.NetconfMessageFactory;
-import org.opendaylight.protocol.framework.ProtocolHandlerFactory;
-import org.opendaylight.protocol.framework.ProtocolMessageDecoder;
-import org.opendaylight.protocol.framework.ProtocolMessageEncoder;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
 import org.opendaylight.protocol.framework.ReconnectStrategy;
-import org.opendaylight.protocol.framework.SessionListener;
+import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
 import org.opendaylight.protocol.framework.SessionListenerFactory;
 
-import java.io.IOException;
-import java.net.InetSocketAddress;
+import com.google.common.base.Optional;
 
 public class NetconfSshClientDispatcher extends NetconfClientDispatcher {
 
-    private AuthenticationHandler authHandler;
-    private HashedWheelTimer timer;
-    private NetconfClientSessionNegotiatorFactory negotatorFactory;
+    private final AuthenticationHandler authHandler;
+    private final HashedWheelTimer timer;
+    private final NetconfClientSessionNegotiatorFactory negotiatorFactory;
 
     public NetconfSshClientDispatcher(AuthenticationHandler authHandler, EventLoopGroup bossGroup,
             EventLoopGroup workerGroup, long connectionTimeoutMillis) {
         super(bossGroup, workerGroup, connectionTimeoutMillis);
         this.authHandler = authHandler;
         this.timer = new HashedWheelTimer();
-        this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.<String>absent(), connectionTimeoutMillis);
+        this.negotiatorFactory = new NetconfClientSessionNegotiatorFactory(timer,
+                Optional.<NetconfHelloMessageAdditionalHeader> absent(), connectionTimeoutMillis);
     }
 
     public NetconfSshClientDispatcher(AuthenticationHandler authHandler, EventLoopGroup bossGroup,
-            EventLoopGroup workerGroup, String additionalHeader, long socketTimeoutMillis) {
+            EventLoopGroup workerGroup, NetconfHelloMessageAdditionalHeader additionalHeader, long socketTimeoutMillis) {
         super(bossGroup, workerGroup, additionalHeader, socketTimeoutMillis);
         this.authHandler = authHandler;
         this.timer = new HashedWheelTimer();
-        this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader), socketTimeoutMillis);
+        this.negotiatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader),
+                socketTimeoutMillis);
     }
 
+    @Override
     public Future<NetconfClientSession> createClient(InetSocketAddress address,
             final NetconfClientSessionListener sessionListener, ReconnectStrategy strat) {
         return super.createClient(address, strat, new PipelineInitializer<NetconfClientSession>() {
 
             @Override
             public void initializeChannel(SocketChannel arg0, Promise<NetconfClientSession> arg1) {
-                new NetconfSshClientInitializer(authHandler, negotatorFactory, sessionListener).initialize(arg0, arg1);
+                new NetconfSshClientInitializer(authHandler, negotiatorFactory, sessionListener).initialize(arg0, arg1);
             }
 
         });
     }
 
-    private static final class NetconfSshClientInitializer extends AbstractChannelInitializer {
+    @Override
+    public Future<Void> createReconnectingClient(final InetSocketAddress address,
+            final NetconfClientSessionListener listener,
+            final ReconnectStrategyFactory connectStrategyFactory, final ReconnectStrategy reestablishStrategy) {
+        final NetconfSshClientInitializer init = new NetconfSshClientInitializer(authHandler, negotiatorFactory, listener);
+
+        return super.createReconnectingClient(address, connectStrategyFactory, reestablishStrategy,
+                new PipelineInitializer<NetconfClientSession>() {
+            @Override
+            public void initializeChannel(final SocketChannel ch, final Promise<NetconfClientSession> promise) {
+                init.initialize(ch, promise);
+            }
+        });
+    }
+
+    private static final class NetconfSshClientInitializer extends AbstractChannelInitializer<NetconfClientSession> {
 
-        private final NetconfHandlerFactory handlerFactory;
         private final AuthenticationHandler authenticationHandler;
         private final NetconfClientSessionNegotiatorFactory negotiatorFactory;
         private final NetconfClientSessionListener sessionListener;
@@ -77,14 +89,13 @@ public class NetconfSshClientDispatcher extends NetconfClientDispatcher {
         public NetconfSshClientInitializer(AuthenticationHandler authHandler,
                 NetconfClientSessionNegotiatorFactory negotiatorFactory,
                 final NetconfClientSessionListener sessionListener) {
-            this.handlerFactory = new NetconfHandlerFactory(new NetconfMessageFactory());
             this.authenticationHandler = authHandler;
             this.negotiatorFactory = negotiatorFactory;
             this.sessionListener = sessionListener;
         }
 
         @Override
-        public void initialize(SocketChannel ch, Promise<? extends NetconfSession> promise) {
+        public void initialize(SocketChannel ch, Promise<NetconfClientSession> promise) {
             try {
                 Invoker invoker = Invoker.subsystem("netconf");
                 ch.pipeline().addFirst(new SshHandler(authenticationHandler, invoker));
@@ -95,31 +106,15 @@ public class NetconfSshClientDispatcher extends NetconfClientDispatcher {
         }
 
         @Override
-        protected void initializeAfterDecoder(SocketChannel ch, Promise<? extends NetconfSession> promise) {
-            ch.pipeline().addLast("negotiator", negotiatorFactory.getSessionNegotiator(new SessionListenerFactory() {
+        protected void initializeSessionNegotiator(SocketChannel ch,
+                Promise<NetconfClientSession> promise) {
+            ch.pipeline().addAfter(NETCONF_MESSAGE_DECODER,  AbstractChannelInitializer.NETCONF_SESSION_NEGOTIATOR,
+                    negotiatorFactory.getSessionNegotiator(new SessionListenerFactory<NetconfClientSessionListener>() {
                 @Override
-                public SessionListener<NetconfMessage, NetconfClientSession, NetconfTerminationReason> getSessionListener() {
+                public NetconfClientSessionListener getSessionListener() {
                     return sessionListener;
                 }
             }, ch, promise));
-
-        }
-    }
-
-    private static final class NetconfHandlerFactory extends ProtocolHandlerFactory<NetconfMessage> {
-
-        public NetconfHandlerFactory(final NetconfMessageFactory msgFactory) {
-            super(msgFactory);
-        }
-
-        @Override
-        public ChannelHandler[] getEncoders() {
-            return new ChannelHandler[] { new ProtocolMessageEncoder(this.msgFactory) };
-        }
-
-        @Override
-        public ChannelHandler[] getDecoders() {
-            return new ChannelHandler[] { new ProtocolMessageDecoder(this.msgFactory) };
         }
     }
 }
diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/SimpleNetconfClientSessionListener.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/SimpleNetconfClientSessionListener.java
new file mode 100644 (file)
index 0000000..e96161c
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * 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.client;
+
+import io.netty.util.concurrent.Future;
+import io.netty.util.concurrent.GlobalEventExecutor;
+import io.netty.util.concurrent.Promise;
+
+import java.util.ArrayDeque;
+import java.util.Queue;
+
+import javax.annotation.concurrent.GuardedBy;
+
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+public class SimpleNetconfClientSessionListener implements NetconfClientSessionListener {
+    private static final class RequestEntry {
+        final Promise<NetconfMessage> promise;
+        final NetconfMessage request;
+
+        public RequestEntry(Promise<NetconfMessage> future, NetconfMessage request) {
+            this.promise = Preconditions.checkNotNull(future);
+            this.request = Preconditions.checkNotNull(request);
+        }
+    }
+
+    private static final Logger logger = LoggerFactory.getLogger(SimpleNetconfClientSessionListener.class);
+
+    @GuardedBy("this")
+    private final Queue<RequestEntry> requests = new ArrayDeque<>();
+
+    @GuardedBy("this")
+    private NetconfClientSession clientSession;
+
+    @GuardedBy("this")
+    private void dispatchRequest() {
+        while (!requests.isEmpty()) {
+            final RequestEntry e = requests.peek();
+            if (e.promise.setUncancellable()) {
+                logger.debug("Sending message {}", e.request);
+                clientSession.sendMessage(e.request);
+                break;
+            }
+
+            logger.debug("Message {} has been cancelled, skipping it", e.request);
+            requests.poll();
+        }
+    }
+
+    @Override
+    public final synchronized void onSessionUp(NetconfClientSession clientSession) {
+        this.clientSession = Preconditions.checkNotNull(clientSession);
+        logger.debug("Client session {} went up", clientSession);
+        dispatchRequest();
+    }
+
+    private synchronized void tearDown(final Exception cause) {
+        final RequestEntry e = requests.poll();
+        if (e != null) {
+            e.promise.setFailure(cause);
+        }
+
+        this.clientSession = null;
+    }
+
+    @Override
+    public final void onSessionDown(NetconfClientSession clientSession, Exception e) {
+        logger.debug("Client Session {} went down unexpectedly", clientSession, e);
+        tearDown(e);
+    }
+
+    @Override
+    public final void onSessionTerminated(NetconfClientSession clientSession,
+            NetconfTerminationReason netconfTerminationReason) {
+        logger.debug("Client Session {} terminated, reason: {}", clientSession,
+                netconfTerminationReason.getErrorMessage());
+        tearDown(new RuntimeException(netconfTerminationReason.getErrorMessage()));
+    }
+
+    @Override
+    public synchronized void onMessage(NetconfClientSession session, NetconfMessage message) {
+        logger.debug("New message arrived: {}", message);
+
+        final RequestEntry e = requests.poll();
+        if (e != null) {
+            e.promise.setSuccess(message);
+            dispatchRequest();
+        } else {
+            logger.info("Ignoring unsolicited message {}", message);
+        }
+    }
+
+    final synchronized Future<NetconfMessage> sendRequest(NetconfMessage message) {
+        final RequestEntry req = new RequestEntry(GlobalEventExecutor.INSTANCE.<NetconfMessage>newPromise(), message);
+
+        requests.add(req);
+        if (clientSession != null) {
+            dispatchRequest();
+        }
+
+        return req.promise;
+    }
+}
index a3cc10417e389123169abe940d05cddf7f98b85b..1357201f5754d75ee6d7b4874aa78f6a6ceb48d7 100644 (file)
@@ -12,38 +12,78 @@ import io.netty.channel.nio.NioEventLoopGroup;
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
-import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.util.NetconfUtil;
 import org.opendaylight.controller.netconf.util.handler.ssh.authentication.LoginPassword;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
+import java.io.IOException;
 import java.net.InetSocketAddress;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
 
 @Ignore
 public class SSHNetconfClientLiveTest {
+    private static final Logger logger = LoggerFactory.getLogger(SSHNetconfClientLiveTest.class);
 
     NioEventLoopGroup nettyThreadgroup;
     NetconfSshClientDispatcher netconfClientDispatcher;
+    InetSocketAddress address;
+    final int connectionAttempts = 10, attemptMsTimeout = 1000;
+    final int connectionTimeoutMillis = 20000;
 
     @Before
     public void setUp() {
         nettyThreadgroup = new NioEventLoopGroup();
+
         netconfClientDispatcher = new NetconfSshClientDispatcher(new LoginPassword(
                 System.getProperty("username"), System.getProperty("password")),
-                nettyThreadgroup, nettyThreadgroup, 5000);
+                nettyThreadgroup, nettyThreadgroup, connectionTimeoutMillis);
+
+        address = new InetSocketAddress(System.getProperty("host"), Integer.parseInt(System.getProperty("port")));
     }
 
+    @Ignore
     @Test
     public void test() throws Exception {
-        InetSocketAddress address = new InetSocketAddress(System.getProperty("host"), 830);
-        int connectionAttempts = 10, attemptMsTimeout = 1000;
+        //runnable.run();
+    }
 
-        NetconfClient netconfClient = new NetconfClient("client", address, connectionAttempts,
-            attemptMsTimeout, netconfClientDispatcher);
+    @Test
+    public void testInExecutor() throws Exception {
+        int threads = 4;
+        ExecutorService executorService = Executors.newFixedThreadPool(threads);
+        try {
+            for (int i= 0;i< threads;i++) {
+                InetSocketAddress address = new InetSocketAddress(System.getProperty("host"),
+                        Integer.parseInt(System.getProperty("port")));
+                NetconfRunnable runnable = new NetconfRunnable(address);
+                executorService.execute(runnable);
+            }
+            executorService.shutdown();
+            executorService.awaitTermination(1, TimeUnit.MINUTES);
 
-        netconfClient.getCapabilities();
 
-        NetconfMessage netconfMessage = NetconfUtil.createMessage(getClass().getResourceAsStream("/get_schema.xml"));
-        NetconfMessage response = netconfClient.sendMessage(netconfMessage);
-        NetconfUtil.checkIsMessageOk(response);
+        } finally {
+            executorService.shutdownNow();
+        }
     }
+
+    class NetconfRunnable implements Runnable {
+        private final InetSocketAddress address;
+
+        NetconfRunnable(InetSocketAddress address) {
+            this.address = address;
+        }
+
+        @Override
+        public void run() {
+            try (NetconfClient netconfClient = new NetconfClient(address.toString(), address, connectionAttempts,
+                    attemptMsTimeout, netconfClientDispatcher);) {
+                logger.info("OK {}", address);
+            } catch (InterruptedException | IOException e) {
+                logger.error("Failed {}", address, e);
+            }
+        }
+    };
 }
index 7c5bd0cb21dcc25988c3e66c17f7821b3a780d11..ee9009762e8cda9d3f2ac8896f2df8bced568f83 100644 (file)
@@ -12,14 +12,14 @@ import io.netty.channel.ChannelFuture;
 import io.netty.channel.EventLoopGroup;
 import io.netty.channel.socket.SocketChannel;
 import io.netty.util.concurrent.Promise;
-import org.opendaylight.controller.netconf.api.NetconfSession;
+
+import java.net.InetSocketAddress;
+
 import org.opendaylight.controller.netconf.impl.util.DeserializerExceptionHandler;
 import org.opendaylight.controller.netconf.util.AbstractChannelInitializer;
 import org.opendaylight.protocol.framework.AbstractDispatcher;
 
-import java.net.InetSocketAddress;
-
-public class NetconfServerDispatcher extends AbstractDispatcher<NetconfSession, NetconfServerSessionListener> {
+public class NetconfServerDispatcher extends AbstractDispatcher<NetconfServerSession, NetconfServerSessionListener> {
 
     private final ServerChannelInitializer initializer;
 
@@ -31,15 +31,17 @@ public class NetconfServerDispatcher extends AbstractDispatcher<NetconfSession,
 
     public ChannelFuture createServer(InetSocketAddress address) {
 
-        return super.createServer(address, new PipelineInitializer<NetconfSession>() {
+        return super.createServer(address, new PipelineInitializer<NetconfServerSession>() {
             @Override
-            public void initializeChannel(final SocketChannel ch, final Promise<NetconfSession> promise) {
+            public void initializeChannel(final SocketChannel ch, final Promise<NetconfServerSession> promise) {
                 initializer.initialize(ch, promise);
             }
         });
     }
 
-    public static class ServerChannelInitializer extends AbstractChannelInitializer {
+    public static class ServerChannelInitializer extends AbstractChannelInitializer<NetconfServerSession> {
+
+        public static final String DESERIALIZER_EX_HANDLER_KEY = "deserializerExHandler";
 
         private final NetconfServerSessionNegotiatorFactory negotiatorFactory;
         private final NetconfServerSessionListenerFactory listenerFactory;
@@ -51,11 +53,15 @@ public class NetconfServerDispatcher extends AbstractDispatcher<NetconfSession,
         }
 
         @Override
-        protected void initializeAfterDecoder(SocketChannel ch, Promise<? extends NetconfSession> promise) {
-            ch.pipeline().addLast("deserializerExHandler", new DeserializerExceptionHandler());
-            ch.pipeline().addLast("negotiator", negotiatorFactory.getSessionNegotiator(listenerFactory, ch, promise));
+        protected void initializeMessageDecoder(SocketChannel ch) {
+            super.initializeMessageDecoder(ch);
+            ch.pipeline().addLast(DESERIALIZER_EX_HANDLER_KEY, new DeserializerExceptionHandler());
         }
 
+        @Override
+        protected void initializeSessionNegotiator(SocketChannel ch, Promise<NetconfServerSession> promise) {
+            ch.pipeline().addAfter(DESERIALIZER_EX_HANDLER_KEY, AbstractChannelInitializer.NETCONF_SESSION_NEGOTIATOR, negotiatorFactory.getSessionNegotiator(listenerFactory, ch, promise));
+        }
     }
 
 }
index 4cc05b7b42fa40a17f9552e2d459b1bfdb85cea6..9ddc64f1a16934b95c6a3bd69410eef554e4313b 100644 (file)
@@ -15,9 +15,9 @@ import java.util.Date;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import org.opendaylight.controller.netconf.api.NetconfSession;
+import org.opendaylight.controller.netconf.api.AbstractNetconfSession;
 import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
-import org.opendaylight.protocol.framework.SessionListener;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.DomainName;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Host;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.NetconfTcp;
@@ -35,17 +35,17 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Preconditions;
 
-public class NetconfServerSession extends NetconfSession implements NetconfManagementSession {
+public final class NetconfServerSession extends AbstractNetconfSession<NetconfServerSession, NetconfServerSessionListener> implements NetconfManagementSession {
 
     private static final Logger logger = LoggerFactory.getLogger(NetconfServerSession.class);
 
-    private final NetconfServerSessionNegotiator.AdditionalHeader header;
+    private final NetconfHelloMessageAdditionalHeader header;
 
     private Date loginTime;
     private long inRpcSuccess, inRpcFail, outRpcError;
 
-    public NetconfServerSession(SessionListener sessionListener, Channel channel, long sessionId,
-            NetconfServerSessionNegotiator.AdditionalHeader header) {
+    public NetconfServerSession(NetconfServerSessionListener sessionListener, Channel channel, long sessionId,
+            NetconfHelloMessageAdditionalHeader header) {
         super(sessionListener, channel, sessionId);
         this.header = header;
         logger.debug("Session {} created", toString());
@@ -72,6 +72,9 @@ public class NetconfServerSession extends NetconfSession implements NetconfManag
 
     public static final String ISO_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";
 
+    private static final String dateTimePatternString = DateAndTime.PATTERN_CONSTANTS.get(0);
+    private static final Pattern dateTimePattern = Pattern.compile(dateTimePatternString);
+
     @Override
     public Session toManagementSession() {
         SessionBuilder builder = new SessionBuilder();
@@ -81,16 +84,16 @@ public class NetconfServerSession extends NetconfSession implements NetconfManag
 
         Preconditions.checkState(DateAndTime.PATTERN_CONSTANTS.size() == 1);
         String formattedDateTime = formatDateTime(loginTime);
-        String pattern = DateAndTime.PATTERN_CONSTANTS.get(0);
-        Matcher matcher = Pattern.compile(pattern).matcher(formattedDateTime);
-        Preconditions.checkState(matcher.matches(), "Formatted datetime %s does not match pattern %s", formattedDateTime, pattern);
+
+        Matcher matcher = dateTimePattern.matcher(formattedDateTime);
+        Preconditions.checkState(matcher.matches(), "Formatted datetime %s does not match pattern %s", formattedDateTime, dateTimePattern);
         builder.setLoginTime(new DateAndTime(formattedDateTime));
 
         builder.setInBadRpcs(new ZeroBasedCounter32(inRpcFail));
         builder.setInRpcs(new ZeroBasedCounter32(inRpcSuccess));
         builder.setOutRpcErrors(new ZeroBasedCounter32(outRpcError));
 
-        builder.setUsername(header.getUsername());
+        builder.setUsername(header.getUserName());
         builder.setTransport(getTransportForString(header.getTransport()));
 
         builder.setOutNotifications(new ZeroBasedCounter32(0L));
@@ -98,7 +101,7 @@ public class NetconfServerSession extends NetconfSession implements NetconfManag
         builder.setKey(new SessionKey(getSessionId()));
 
         Session1Builder builder1 = new Session1Builder();
-        builder1.setSessionIdentifier(header.getSessionType());
+        builder1.setSessionIdentifier(header.getSessionIdentifier());
         builder.addAugmentation(Session1.class, builder1.build());
 
         return builder.build();
@@ -106,9 +109,9 @@ public class NetconfServerSession extends NetconfSession implements NetconfManag
 
     private Class<? extends Transport> getTransportForString(String transport) {
         switch(transport) {
-            case "ssh" : return NetconfSsh.class;
-            case "tcp" : return NetconfTcp.class;
-            default: throw new IllegalArgumentException("Unknown transport type " + transport);
+        case "ssh" : return NetconfSsh.class;
+        case "tcp" : return NetconfTcp.class;
+        default: throw new IllegalArgumentException("Unknown transport type " + transport);
         }
     }
 
@@ -117,4 +120,8 @@ public class NetconfServerSession extends NetconfSession implements NetconfManag
         return dateFormat.format(loginTime);
     }
 
+    @Override
+    protected NetconfServerSession thisInstance() {
+        return this;
+    }
 }
index 43e55d746a4ee59d1ec9bb35245f74e0edbca018..460288fe33256147a6a55c666cfbbd9dd8181862 100644 (file)
@@ -8,10 +8,11 @@
 
 package org.opendaylight.controller.netconf.impl;
 
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableMap;
+import static com.google.common.base.Preconditions.checkState;
+
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.NetconfSessionListener;
 import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouterImpl;
 import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
@@ -19,25 +20,22 @@ import org.opendaylight.controller.netconf.util.messages.SendErrorExceptionUtil;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
 import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-import org.opendaylight.protocol.framework.SessionListener;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 import org.w3c.dom.Node;
 
-import static com.google.common.base.Preconditions.checkState;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
 
-public class NetconfServerSessionListener implements
-        SessionListener<NetconfMessage, NetconfServerSession, NetconfTerminationReason> {
+public class NetconfServerSessionListener implements NetconfSessionListener<NetconfServerSession> {
+    public static final String MESSAGE_ID = "message-id";
 
     static final Logger logger = LoggerFactory.getLogger(NetconfServerSessionListener.class);
-    public static final String MESSAGE_ID = "message-id";
     private final SessionMonitoringService monitoringService;
+    private final NetconfOperationRouterImpl operationRouter;
 
-    private NetconfOperationRouterImpl operationRouter;
-
-    public NetconfServerSessionListener(NetconfOperationRouterImpl operationRouter,
-                                        SessionMonitoringService monitoringService) {
+    public NetconfServerSessionListener(NetconfOperationRouterImpl operationRouter, SessionMonitoringService monitoringService) {
         this.operationRouter = operationRouter;
         this.monitoringService = monitoringService;
     }
index 91555861dc4aaaa51fdfd69dd24ae9bb834f02e7..1b4dfff42baeb0423597af3c90168592db146724 100644 (file)
@@ -8,86 +8,48 @@
 
 package org.opendaylight.controller.netconf.impl;
 
-import com.google.common.base.Optional;
-import io.netty.channel.Channel;
-import io.netty.util.Timer;
-import io.netty.util.concurrent.Promise;
-import org.opendaylight.controller.netconf.api.NetconfMessage;
+import java.net.InetSocketAddress;
+
 import org.opendaylight.controller.netconf.api.NetconfServerSessionPreferences;
-import org.opendaylight.controller.netconf.impl.util.AdditionalHeaderUtil;
 import org.opendaylight.controller.netconf.util.AbstractNetconfSessionNegotiator;
-import org.opendaylight.protocol.framework.SessionListener;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.net.InetSocketAddress;
+import com.google.common.base.Optional;
+
+import io.netty.channel.Channel;
+import io.netty.util.Timer;
+import io.netty.util.concurrent.Promise;
 
 public class NetconfServerSessionNegotiator extends
-        AbstractNetconfSessionNegotiator<NetconfServerSessionPreferences, NetconfServerSession> {
+        AbstractNetconfSessionNegotiator<NetconfServerSessionPreferences, NetconfServerSession, NetconfServerSessionListener> {
 
     static final Logger logger = LoggerFactory.getLogger(NetconfServerSessionNegotiator.class);
 
     protected NetconfServerSessionNegotiator(NetconfServerSessionPreferences sessionPreferences,
-            Promise<NetconfServerSession> promise, Channel channel, Timer timer, SessionListener sessionListener,
+            Promise<NetconfServerSession> promise, Channel channel, Timer timer, NetconfServerSessionListener sessionListener,
             long connectionTimeoutMillis) {
         super(sessionPreferences, promise, channel, timer, sessionListener, connectionTimeoutMillis);
     }
 
     @Override
-    protected NetconfServerSession getSession(SessionListener sessionListener, Channel channel, NetconfMessage message) {
-        Optional<String> additionalHeader = message.getAdditionalHeader();
+    protected NetconfServerSession getSession(NetconfServerSessionListener sessionListener, Channel channel, NetconfHelloMessage message) {
+        Optional<NetconfHelloMessageAdditionalHeader> additionalHeader = message.getAdditionalHeader();
 
-        AdditionalHeader parsedHeader;
+        NetconfHelloMessageAdditionalHeader parsedHeader;
         if (additionalHeader.isPresent()) {
-            parsedHeader = AdditionalHeaderUtil.fromString(additionalHeader.get());
+            parsedHeader = additionalHeader.get();
         } else {
-            parsedHeader = new AdditionalHeader("unknown", ((InetSocketAddress)channel.localAddress()).getHostString(),
+            InetSocketAddress inetSocketAddress = (InetSocketAddress) channel.localAddress();
+            parsedHeader = new NetconfHelloMessageAdditionalHeader("unknown", inetSocketAddress.getHostString(), Integer.toString(inetSocketAddress.getPort()),
                     "tcp", "client");
         }
+
         logger.debug("Additional header from hello parsed as {} from {}", parsedHeader, additionalHeader);
 
         return new NetconfServerSession(sessionListener, channel, sessionPreferences.getSessionId(), parsedHeader);
     }
 
-    public static class AdditionalHeader {
-
-        private final String username;
-        private final String address;
-        private final String transport;
-        private final String sessionIdentifier;
-
-        public AdditionalHeader(String userName, String hostAddress, String transport, String sessionIdentifier) {
-            this.address = hostAddress;
-            this.username = userName;
-            this.transport = transport;
-            this.sessionIdentifier = sessionIdentifier;
-        }
-
-        String getUsername() {
-            return username;
-        }
-
-        String getAddress() {
-            return address;
-        }
-
-        String getTransport() {
-            return transport;
-        }
-
-        String getSessionType() {
-            return sessionIdentifier;
-        }
-
-        @Override
-        public String toString() {
-            final StringBuffer sb = new StringBuffer("AdditionalHeader{");
-            sb.append("username='").append(username).append('\'');
-            sb.append(", address='").append(address).append('\'');
-            sb.append(", transport='").append(transport).append('\'');
-            sb.append('}');
-            return sb.toString();
-        }
-    }
-
-}
+   }
index 98462b8025ce965b596cfd323484164eaa7c97d1..e052f61cc97dd7dce5a1e048f8f7f9938667df09 100644 (file)
@@ -12,11 +12,11 @@ import com.google.common.base.Preconditions;
 import io.netty.channel.Channel;
 import io.netty.util.Timer;
 import io.netty.util.concurrent.Promise;
-import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.NetconfServerSessionPreferences;
 import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListener;
 import org.opendaylight.controller.netconf.util.NetconfUtil;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
 import org.opendaylight.controller.netconf.util.xml.XMLNetconfUtil;
 import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
@@ -31,7 +31,7 @@ import javax.xml.xpath.XPathConstants;
 import javax.xml.xpath.XPathExpression;
 import java.io.InputStream;
 
-public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorFactory {
+public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorFactory<NetconfHelloMessage, NetconfServerSession, NetconfServerSessionListener> {
 
     public static final String SERVER_HELLO_XML_LOCATION = "/server_hello.xml";
 
@@ -59,8 +59,8 @@ public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorF
     }
 
     @Override
-    public SessionNegotiator getSessionNegotiator(SessionListenerFactory sessionListenerFactory, Channel channel,
-            Promise promise) {
+    public SessionNegotiator<NetconfServerSession> getSessionNegotiator(SessionListenerFactory<NetconfServerSessionListener> sessionListenerFactory, Channel channel,
+            Promise<NetconfServerSession> promise) {
         long sessionId = idProvider.getNextSessionId();
 
         NetconfServerSessionPreferences proposal = new NetconfServerSessionPreferences(createHelloMessage(sessionId),
@@ -74,7 +74,7 @@ public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorF
     private static final XPathExpression capabilitiesXPath = XMLNetconfUtil
             .compileXPath("/netconf:hello/netconf:capabilities");
 
-    private NetconfMessage createHelloMessage(long sessionId) {
+    private NetconfHelloMessage createHelloMessage(long sessionId) {
         Document helloMessageTemplate = getHelloTemplateClone();
 
         // change session ID
@@ -93,10 +93,10 @@ public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorF
             capabilityElement.setTextContent(capability);
             capabilitiesElement.appendChild(capabilityElement);
         }
-        return new NetconfMessage(helloMessageTemplate);
+        return new NetconfHelloMessage(helloMessageTemplate);
     }
 
     private synchronized Document getHelloTemplateClone() {
-        return (Document) this.helloMessageTemplate.cloneNode(true);
+        return (Document) helloMessageTemplate.cloneNode(true);
     }
 }
index cc503f60c3938947b8acb29882a9cd161bafda5c..1438515f040e41c547a8742010aec37b6ab2471b 100644 (file)
@@ -8,10 +8,8 @@
 
 package org.opendaylight.controller.netconf.impl.mapping.operations;
 
-import org.opendaylight.controller.netconf.api.NetconfSession;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
-import org.opendaylight.controller.netconf.mapping.api.DefaultNetconfOperation;
 import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
 import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
@@ -19,9 +17,8 @@ import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
-public class DefaultCloseSession extends AbstractNetconfOperation implements DefaultNetconfOperation {
+public class DefaultCloseSession extends AbstractNetconfOperation {
     public static final String CLOSE_SESSION = "close-session";
-    private NetconfSession netconfSession;
 
     public DefaultCloseSession(String netconfSessionIdForReporting) {
         super(netconfSessionIdForReporting);
@@ -48,13 +45,4 @@ public class DefaultCloseSession extends AbstractNetconfOperation implements Def
         opRouter.close();
         return document.createElement(XmlNetconfConstants.OK);
     }
-
-    @Override
-    public void setNetconfSession(NetconfSession s) {
-        this.netconfSession = s;
-    }
-
-    public NetconfSession getNetconfSession() {
-        return netconfSession;
-    }
 }
index f34529d53fe0549c7ce5ad6ce6b995386c00ab64..904f3f613e43549134eafcf7fc733591f32f4a2f 100644 (file)
@@ -11,11 +11,9 @@ package org.opendaylight.controller.netconf.impl.mapping.operations;
 import java.util.HashMap;
 import java.util.Map;
 
-import org.opendaylight.controller.netconf.api.NetconfSession;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
 import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
-import org.opendaylight.controller.netconf.mapping.api.DefaultNetconfOperation;
 import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
 import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
@@ -29,22 +27,19 @@ import org.w3c.dom.Element;
 import com.google.common.base.Optional;
 import com.google.common.collect.Maps;
 
-public final class DefaultGetSchema extends AbstractNetconfOperation implements DefaultNetconfOperation {
-
-    private final CapabilityProvider cap;
-    private NetconfSession netconfSession;
+public final class DefaultGetSchema extends AbstractNetconfOperation {
+    public static final String GET_SCHEMA = "get-schema";
+    public static final String IDENTIFIER = "identifier";
+    public static final String VERSION = "version";
 
     private static final Logger logger = LoggerFactory.getLogger(DefaultGetSchema.class);
+    private final CapabilityProvider cap;
 
     public DefaultGetSchema(CapabilityProvider cap, String netconfSessionIdForReporting) {
         super(netconfSessionIdForReporting);
         this.cap = cap;
     }
 
-    public static final String GET_SCHEMA = "get-schema";
-    public static final String IDENTIFIER = "identifier";
-    public static final String VERSION = "version";
-
     @Override
     protected HandlingPriority canHandle(String netconfOperationName, String namespace) {
         if (netconfOperationName.equals("get-schema") == false)
@@ -117,15 +112,6 @@ public final class DefaultGetSchema extends AbstractNetconfOperation implements
             } else {
                 version = Optional.absent();
             }
-
         }
     }
-
-    public void setNetconfSession(NetconfSession s) {
-        this.netconfSession = s;
-    }
-
-    public NetconfSession getNetconfSession() {
-        return netconfSession;
-    }
 }
index d70a15c18bdf933d56df70d7f7e9be07df6653da..ece9d47ee9fcfe3a0e485347d450d6a7e7fd83e2 100644 (file)
@@ -7,12 +7,18 @@
  */
 package org.opendaylight.controller.netconf.impl.osgi;
 
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import org.opendaylight.controller.netconf.api.NetconfSession;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
+import org.opendaylight.controller.netconf.api.NetconfSession;
 import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
 import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
 import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCloseSession;
@@ -31,14 +37,9 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.TreeSet;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
 
 public class NetconfOperationRouterImpl implements NetconfOperationRouter {
 
@@ -55,24 +56,19 @@ public class NetconfOperationRouterImpl implements NetconfOperationRouter {
     public NetconfOperationRouterImpl(NetconfOperationServiceSnapshot netconfOperationServiceSnapshot,
             CapabilityProvider capabilityProvider, DefaultCommitNotificationProducer commitNotifier) {
 
-        this.netconfOperationServiceSnapshot = netconfOperationServiceSnapshot;
+        this.netconfOperationServiceSnapshot = Preconditions.checkNotNull(netconfOperationServiceSnapshot);
+        this.capabilityProvider = Preconditions.checkNotNull(capabilityProvider);
 
-        this.capabilityProvider = capabilityProvider;
-
-        Set<NetconfOperation> defaultNetconfOperations = Sets.newHashSet();
-        defaultNetconfOperations.add(new DefaultGetSchema(capabilityProvider, netconfOperationServiceSnapshot
-                .getNetconfSessionIdForReporting()));
-        defaultNetconfOperations.add(new DefaultCloseSession(netconfOperationServiceSnapshot
-                .getNetconfSessionIdForReporting()));
-        defaultNetconfOperations.add(new DefaultStartExi(netconfOperationServiceSnapshot
-                .getNetconfSessionIdForReporting()));
-        defaultNetconfOperations.add(new DefaultStopExi(netconfOperationServiceSnapshot
-                .getNetconfSessionIdForReporting()));
+        final String sessionId = netconfOperationServiceSnapshot.getNetconfSessionIdForReporting();
+        final Set<NetconfOperation> defaultNetconfOperations = Sets.newHashSet();
+        defaultNetconfOperations.add(new DefaultGetSchema(capabilityProvider, sessionId));
+        defaultNetconfOperations.add(new DefaultCloseSession(sessionId));
+        defaultNetconfOperations.add(new DefaultStartExi(sessionId));
+        defaultNetconfOperations.add(new DefaultStopExi(sessionId));
 
         allNetconfOperations = getAllNetconfOperations(defaultNetconfOperations, netconfOperationServiceSnapshot);
 
-        DefaultCommit defaultCommit = new DefaultCommit(commitNotifier, capabilityProvider,
-                netconfOperationServiceSnapshot.getNetconfSessionIdForReporting());
+        DefaultCommit defaultCommit = new DefaultCommit(commitNotifier, capabilityProvider, sessionId);
         Set<NetconfOperationFilter> defaultFilters = Sets.<NetconfOperationFilter> newHashSet(defaultCommit);
         allSortedFilters = getAllNetconfFilters(defaultFilters, netconfOperationServiceSnapshot);
     }
@@ -238,10 +234,6 @@ public class NetconfOperationRouterImpl implements NetconfOperationRouter {
     private class NetconfOperationExecution implements NetconfOperationFilterChain {
         private final NetconfOperation operationWithHighestPriority;
 
-        private NetconfOperationExecution(NetconfOperation operationWithHighestPriority) {
-            this.operationWithHighestPriority = operationWithHighestPriority;
-        }
-
         public NetconfOperationExecution(TreeMap<HandlingPriority, Set<NetconfOperation>> sortedPriority,
                 HandlingPriority highestFoundPriority) {
             operationWithHighestPriority = sortedPriority.get(highestFoundPriority).iterator().next();
diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/util/AdditionalHeaderUtil.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/util/AdditionalHeaderUtil.java
deleted file mode 100644 (file)
index 5c630dd..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.impl.util;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiator.AdditionalHeader;
-
-import com.google.common.base.Preconditions;
-
-public class AdditionalHeaderUtil {
-
-    private static final Pattern pattern = Pattern
-            .compile("\\[(?<username>[^;]+);(?<address>[0-9\\.]+)[:/](?<port>[0-9]+);(?<transport>[a-z]+)[^\\]]+\\]");
-    private static final Pattern customHeaderPattern = Pattern
-            .compile("\\[(?<username>[^;]+);(?<address>[0-9\\.]+)[:/](?<port>[0-9]+);(?<transport>[a-z]+);(?<sessionIdentifier>[a-z]+)[^\\]]+\\]");
-
-    public static AdditionalHeader fromString(String additionalHeader) {
-        additionalHeader = additionalHeader.trim();
-        Matcher matcher = pattern.matcher(additionalHeader);
-        Matcher matcher2 = customHeaderPattern.matcher(additionalHeader);
-        Preconditions.checkArgument(matcher.matches(), "Additional header in wrong format %s, expected %s",
-                additionalHeader, pattern);
-        String username = matcher.group("username");
-        String address = matcher.group("address");
-        String transport = matcher.group("transport");
-        String sessionIdentifier = "client";
-        if (matcher2.matches()) {
-            sessionIdentifier = matcher2.group("sessionIdentifier");
-        }
-        return new AdditionalHeader(username, address, transport, sessionIdentifier);
-    }
-
-}
index 97d9a98b5777b01e37468c00a98e8ea54f4dc889..c2dcd679210f1d66cd055e48a9c05494d3d8d374 100644 (file)
@@ -10,15 +10,15 @@ package org.opendaylight.controller.netconf.impl;
 import junit.framework.Assert;
 
 import org.junit.Test;
-import org.opendaylight.controller.netconf.impl.util.AdditionalHeaderUtil;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
 
 public class AdditionalHeaderParserTest {
 
     @Test
     public void testParsing() throws Exception {
         String s = "[netconf;10.12.0.102:48528;ssh;;;;;;]";
-        NetconfServerSessionNegotiator.AdditionalHeader header = AdditionalHeaderUtil.fromString(s);
-        Assert.assertEquals("netconf", header.getUsername());
+        NetconfHelloMessageAdditionalHeader header = NetconfHelloMessageAdditionalHeader.fromString(s);
+        Assert.assertEquals("netconf", header.getUserName());
         Assert.assertEquals("10.12.0.102", header.getAddress());
         Assert.assertEquals("ssh", header.getTransport());
     }
@@ -26,8 +26,8 @@ public class AdditionalHeaderParserTest {
     @Test
     public void testParsing2() throws Exception {
         String s = "[tomas;10.0.0.0/10000;tcp;1000;1000;;/home/tomas;;]";
-        NetconfServerSessionNegotiator.AdditionalHeader header = AdditionalHeaderUtil.fromString(s);
-        Assert.assertEquals("tomas", header.getUsername());
+        NetconfHelloMessageAdditionalHeader header = NetconfHelloMessageAdditionalHeader.fromString(s);
+        Assert.assertEquals("tomas", header.getUserName());
         Assert.assertEquals("10.0.0.0", header.getAddress());
         Assert.assertEquals("tcp", header.getTransport());
     }
@@ -35,6 +35,6 @@ public class AdditionalHeaderParserTest {
     @Test(expected = IllegalArgumentException.class)
     public void testParsingNoUsername() throws Exception {
         String s = "[10.12.0.102:48528;ssh;;;;;;]";
-        AdditionalHeaderUtil.fromString(s);
+        NetconfHelloMessageAdditionalHeader.fromString(s);
     }
 }
index 0ef2c285e407ac65b9eb62e0bbfc2d14b555c242..c0d52ad85e87560a6dd0b645a40b809255f663fb 100644 (file)
@@ -37,6 +37,7 @@ import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationFilter;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
 import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.slf4j.Logger;
@@ -100,7 +101,8 @@ public class ConcurrentClientsTest {
         }
 
         nettyGroup = new NioEventLoopGroup();
-        netconfClientDispatcher = new NetconfClientDispatcher( nettyGroup, nettyGroup, 5000);
+        NetconfHelloMessageAdditionalHeader additionalHeader = new NetconfHelloMessageAdditionalHeader("uname", "10.10.10.1", "830", "tcp", "client");
+        netconfClientDispatcher = new NetconfClientDispatcher( nettyGroup, nettyGroup, additionalHeader, 5000);
 
         NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
         factoriesListener.onAddNetconfOperationServiceFactory(mockOpF());
index baf2d7d761373a4dfb00895eed62a4d16b0470ee..85bccba14ff01da5d559ad83ff6080e0ef5b6b42 100644 (file)
@@ -13,30 +13,28 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
-
-import java.util.Queue;
-
 import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
 import io.netty.channel.embedded.EmbeddedChannel;
 
+import java.util.Queue;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.util.handler.FramingMechanismHandlerFactory;
 import org.opendaylight.controller.netconf.util.handler.NetconfMessageAggregator;
 import org.opendaylight.controller.netconf.util.handler.NetconfMessageChunkDecoder;
+import org.opendaylight.controller.netconf.util.handler.NetconfMessageToXMLEncoder;
+import org.opendaylight.controller.netconf.util.handler.NetconfXMLToMessageDecoder;
 import org.opendaylight.controller.netconf.util.messages.FramingMechanism;
 import org.opendaylight.controller.netconf.util.messages.NetconfMessageConstants;
-import org.opendaylight.controller.netconf.util.messages.NetconfMessageFactory;
 import org.opendaylight.controller.netconf.util.messages.NetconfMessageHeader;
 import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
-import org.opendaylight.protocol.framework.ProtocolMessageDecoder;
-import org.opendaylight.protocol.framework.ProtocolMessageEncoder;
 
 public class MessageParserTest {
 
     private NetconfMessage msg;
-    private NetconfMessageFactory msgFactory = new NetconfMessageFactory();
 
     @Before
     public void setUp() throws Exception {
@@ -47,16 +45,20 @@ public class MessageParserTest {
     public void testChunkedFramingMechanismOnPipeline() throws Exception {
         EmbeddedChannel testChunkChannel = new EmbeddedChannel(
                 FramingMechanismHandlerFactory.createHandler(FramingMechanism.CHUNK),
-                new ProtocolMessageEncoder<NetconfMessage>(msgFactory),
+                new NetconfMessageToXMLEncoder(),
 
                 new NetconfMessageAggregator(FramingMechanism.CHUNK), new NetconfMessageChunkDecoder(),
-                new ProtocolMessageDecoder<NetconfMessage>(msgFactory));
+                new NetconfXMLToMessageDecoder());
 
         testChunkChannel.writeOutbound(this.msg);
         Queue<Object> messages = testChunkChannel.outboundMessages();
         assertFalse(messages.isEmpty());
 
-        int msgLength = this.msgFactory.put(this.msg).length;
+        final NetconfMessageToXMLEncoder enc = new NetconfMessageToXMLEncoder();
+        final ByteBuf out = Unpooled.buffer();
+        enc.encode(null, msg, out);
+        int msgLength = out.readableBytes();
+
         int chunkCount = msgLength / NetconfMessageConstants.MAX_CHUNK_SIZE;
         if ((msgLength % NetconfMessageConstants.MAX_CHUNK_SIZE) != 0) {
             chunkCount++;
@@ -92,8 +94,8 @@ public class MessageParserTest {
     public void testEOMFramingMechanismOnPipeline() throws Exception {
         EmbeddedChannel testChunkChannel = new EmbeddedChannel(
                 FramingMechanismHandlerFactory.createHandler(FramingMechanism.EOM),
-                new ProtocolMessageEncoder<NetconfMessage>(msgFactory), new NetconfMessageAggregator(
-                        FramingMechanism.EOM), new ProtocolMessageDecoder<NetconfMessage>(msgFactory));
+                new NetconfMessageToXMLEncoder(), new NetconfMessageAggregator(
+                        FramingMechanism.EOM), new NetconfXMLToMessageDecoder());
 
         testChunkChannel.writeOutbound(this.msg);
         ByteBuf recievedOutbound = (ByteBuf) testChunkChannel.readOutbound();
index 954da5f4874a03c10f772822a163750d451f0e6b..fce3f70e73b346bc94e2fb306bdf64d7c25aff3d 100644 (file)
@@ -8,12 +8,33 @@
 
 package org.opendaylight.controller.netconf.it;
 
-import ch.ethz.ssh2.Connection;
-import ch.ethz.ssh2.Session;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
+import static java.util.Collections.emptyList;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 import io.netty.channel.ChannelFuture;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.management.ManagementFactory;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+
+import javax.management.ObjectName;
+import javax.xml.parsers.ParserConfigurationException;
+
 import junit.framework.Assert;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Ignore;
@@ -52,26 +73,11 @@ import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
 import org.xml.sax.SAXException;
 
-import javax.management.ObjectName;
-import javax.xml.parsers.ParserConfigurationException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.management.ManagementFactory;
-import java.net.InetSocketAddress;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
+import ch.ethz.ssh2.Connection;
+import ch.ethz.ssh2.Session;
 
-import static java.util.Collections.emptyList;
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertTrue;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
 
 public class NetconfITTest extends AbstractNetconfConfigTest {
 
@@ -85,7 +91,7 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
     private static final String PASSWORD = "netconf";
 
     private NetconfMessage getConfig, getConfigCandidate, editConfig,
-            closeSession, startExi, stopExi;
+    closeSession, startExi, stopExi;
     private DefaultCommitNotificationProducer commitNot;
     private NetconfServerDispatcher dispatch;
 
@@ -304,7 +310,7 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
 
         }
     }
-    */
+     */
 
     @Test
     public void testCloseSession() throws Exception {
@@ -350,12 +356,12 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
         assertEquals("ok", XmlElement.fromDomDocument(rpcReply).getOnlyChildElement().getName());
     }
 
-    private Document assertGetConfigWorks(final NetconfClient netconfClient) throws InterruptedException {
+    private Document assertGetConfigWorks(final NetconfClient netconfClient) throws InterruptedException, ExecutionException, TimeoutException {
         return assertGetConfigWorks(netconfClient, this.getConfig);
     }
 
     private Document assertGetConfigWorks(final NetconfClient netconfClient, final NetconfMessage getConfigMessage)
-            throws InterruptedException {
+            throws InterruptedException, ExecutionException, TimeoutException {
         final NetconfMessage rpcReply = netconfClient.sendMessage(getConfigMessage);
         assertNotNull(rpcReply);
         assertEquals("data", XmlElement.fromDomDocument(rpcReply.getDocument()).getOnlyChildElement().getName());
@@ -423,19 +429,20 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
         sess.getStdin().write(XmlUtil.toString(this.getConfig.getDocument()).getBytes());
 
         new Thread(){
-           public void run(){
-               while (true){
-                 byte[] bytes = new byte[1024];
-                   int c = 0;
-                   try {
-                       c = sess.getStdout().read(bytes);
-                   } catch (IOException e) {
-                       e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
-                   }
-                   logger.info("got data:"+bytes);
-                 if (c == 0) break;
-               }
-           }
+            @Override
+            public void run(){
+                while (true){
+                    byte[] bytes = new byte[1024];
+                    int c = 0;
+                    try {
+                        c = sess.getStdout().read(bytes);
+                    } catch (IOException e) {
+                        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
+                    }
+                    logger.info("got data:"+bytes);
+                    if (c == 0) break;
+                }
+            }
         }.join();
     }
 
index 3a9d3bacc23b49bf7475f03a070c21e387eb4cc1..200cd344a6617b995065b652efca10a6a2a35791 100644 (file)
@@ -9,10 +9,14 @@ package org.opendaylight.controller.netconf.monitoring;
 
 public class MonitoringConstants {
 
-    public static final String NAMESPACE = "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring";
     public static final String MODULE_NAME = "ietf-netconf-monitoring";
     public static final String MODULE_REVISION = "2010-10-04";
 
+    public static final String NAMESPACE = "urn:ietf:params:xml:ns:yang:" + MODULE_NAME;
+    public static final String EXTENSION_NAMESPACE = NAMESPACE + "-extension";
+
+    public static final String EXTENSION_NAMESPACE_PREFIX = "ncme";
+
     public static final String URI = String.format("%s?module=%s&revision=%s", NAMESPACE, MODULE_NAME, MODULE_REVISION);
 
     public static final String NETCONF_MONITORING_XML_ROOT_ELEMENT = "netconf-state";
index 55aee72fda98af82b894a8f6be83a1d339d904ac..8685ef72208b15fd77845b7486724846d67780a4 100644 (file)
@@ -10,6 +10,8 @@ package org.opendaylight.controller.netconf.monitoring.xml.model;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlTransient;
 
+import com.google.common.base.Joiner;
+import org.opendaylight.controller.netconf.monitoring.MonitoringConstants;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.Session1;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.Session;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -69,13 +71,18 @@ final class MonitoringSession {
     public String getTransport() {
         try {
             QName qName = (QName) managementSession.getTransport().getField("QNAME").get(null);
-            return qName.getLocalName();
+            // Add extension prefix if transport type is from extension yang module
+            if (qName.getNamespace().toString().equals(MonitoringConstants.EXTENSION_NAMESPACE)) {
+                return Joiner.on(':').join(MonitoringConstants.EXTENSION_NAMESPACE_PREFIX, qName.getLocalName());
+            } else {
+                return qName.getLocalName();
+            }
         } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
             throw new IllegalArgumentException("Unknown transport type " + managementSession.getTransport(), e);
         }
     }
 
-    @XmlElement(name= "session-identifier")
+    @XmlElement(name= "session-identifier", namespace = MonitoringConstants.EXTENSION_NAMESPACE)
     public String getSessionType() {
         return managementSession.getAugmentation(Session1.class).getSessionIdentifier();
     }
index 85da5975d1f22caaf4485ebea88484e9ad1f242c..a96c3a3836e55309751011af56bcea32f39d069a 100644 (file)
@@ -7,14 +7,16 @@
  */
 @XmlSchema(
         elementFormDefault = XmlNsForm.QUALIFIED,
-//        xmlns = {
-//                @XmlNs(namespaceURI = MonitoringConstants.NAMESPACE, prefix = "")
-//        }
+        xmlns = {
+                @XmlNs(namespaceURI = MonitoringConstants.EXTENSION_NAMESPACE, prefix = MonitoringConstants.EXTENSION_NAMESPACE_PREFIX),
+                @XmlNs(namespaceURI = MonitoringConstants.NAMESPACE, prefix = "")
+        },
         namespace = MonitoringConstants.NAMESPACE
 )
 package org.opendaylight.controller.netconf.monitoring.xml.model;
 
 import org.opendaylight.controller.netconf.monitoring.MonitoringConstants;
 
+import javax.xml.bind.annotation.XmlNs;
 import javax.xml.bind.annotation.XmlNsForm;
 import javax.xml.bind.annotation.XmlSchema;
\ No newline at end of file
index d4462f85d99e2f3cf267b3e7cffca82670b9d0a3..02129574da40ec274a22b077614c38653a14770d 100644 (file)
@@ -13,8 +13,10 @@ import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringServi
 import org.opendaylight.controller.netconf.monitoring.xml.model.NetconfState;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.DomainName;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Host;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.NetconfTcp;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.Session1;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfSsh;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.Transport;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Schemas;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.SchemasBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Sessions;
@@ -39,7 +41,7 @@ public class JaxBSerializerTest {
 
             @Override
             public Sessions getSessions() {
-                return new SessionsBuilder().setSession(Lists.newArrayList(getMockSession())).build();
+                return new SessionsBuilder().setSession(Lists.newArrayList(getMockSession(NetconfTcp.class), getMockSession(NetconfSsh.class))).build();
             }
 
             @Override
@@ -51,7 +53,7 @@ public class JaxBSerializerTest {
         Element xml = new JaxBSerializer().toXml(model);
     }
 
-    private Session getMockSession() {
+    private Session getMockSession(Class<? extends Transport> transportType) {
         Session mocked = mock(Session.class);
         Session1 mockedSession1 = mock(Session1.class);
         doReturn("client").when(mockedSession1).getSessionIdentifier();
@@ -62,7 +64,7 @@ public class JaxBSerializerTest {
         doReturn(new ZeroBasedCounter32(0L)).when(mocked).getInRpcs();
         doReturn(new ZeroBasedCounter32(0L)).when(mocked).getOutNotifications();
         doReturn(new ZeroBasedCounter32(0L)).when(mocked).getOutRpcErrors();
-        doReturn(NetconfSsh.class).when(mocked).getTransport();
+        doReturn(transportType).when(mocked).getTransport();
         doReturn("username").when(mocked).getUsername();
         doReturn(mockedSession1).when(mocked).getAugmentation(Session1.class);
         return mocked;
index d904ad7f269a344600aa04bd2279b9590a0f91d7..3d5318073d8c0e7cc203fd80fa63b6a05ea71e3e 100644 (file)
@@ -30,14 +30,14 @@ public class AuthProvider implements AuthProviderInterface {
 
     public AuthProvider(IUserManager ium,InputStream privateKeyFileInputStream) throws Exception {
 
-        this.um = ium;
-        if (this.um  == null){
+        AuthProvider.um = ium;
+        if (AuthProvider.um  == null){
             throw new Exception("No usermanager service available.");
         }
 
         List<String> roles = new ArrayList<String>(1);
         roles.add(UserLevel.SYSTEMADMIN.toString());
-        this.um.addLocalUser(new UserConfig(DEFAULT_USER, DEFAULT_PASSWORD, roles));
+        AuthProvider.um.addLocalUser(new UserConfig(DEFAULT_USER, DEFAULT_PASSWORD, roles));
 
         try {
             PEM = IOUtils.toString(privateKeyFileInputStream);
@@ -48,10 +48,10 @@ public class AuthProvider implements AuthProviderInterface {
     }
     @Override
     public boolean authenticated(String username, String password)  throws Exception {
-        if (this.um  == null){
+        if (AuthProvider.um  == null){
             throw new Exception("No usermanager service available.");
         }
-        AuthResultEnum authResult = this.um.authenticate(username,password);
+        AuthResultEnum authResult = AuthProvider.um.authenticate(username,password);
         if (authResult.equals(AuthResultEnum.AUTH_ACCEPT) || authResult.equals(AuthResultEnum.AUTH_ACCEPT_LOC)){
             return true;
         }
@@ -69,12 +69,12 @@ public class AuthProvider implements AuthProviderInterface {
 
     @Override
     public void removeUserManagerService() {
-        this.um = null;
+        AuthProvider.um = null;
     }
 
     @Override
     public void addUserManagerService(IUserManager userManagerService) {
-        this.um = userManagerService;
+        AuthProvider.um = userManagerService;
     }
 
 
index 4a3a650ecd9436505e566b2085d4881603f665cf..6628310c970212a0d4f5fa4079ad8356225ed35e 100644 (file)
@@ -30,8 +30,8 @@ public class StubUserManager implements IUserManager{
     private static String password;
 
     public StubUserManager(String user, String password){
-        this.user = user;
-        this.password = password;
+        StubUserManager.user = user;
+        StubUserManager.password = password;
     }
     @Override
     public List<String> getUserRoles(String userName) {
@@ -40,7 +40,7 @@ public class StubUserManager implements IUserManager{
 
     @Override
     public AuthResultEnum authenticate(String username, String password) {
-        if (this.user.equals(username) && this.password.equals(password)){
+        if (StubUserManager.user.equals(username) && StubUserManager.password.equals(password)){
             return AuthResultEnum.AUTH_ACCEPT_LOC;
         }
         return AuthResultEnum.AUTH_REJECT_LOC;
index aeee2fb04baea1c4bd1535d7b677fb1f50957d8e..0910d9403ad98af67427d9dc818e1ddcff216878 100644 (file)
@@ -10,24 +10,47 @@ package org.opendaylight.controller.netconf.util;
 
 import io.netty.channel.socket.SocketChannel;
 import io.netty.util.concurrent.Promise;
+
 import org.opendaylight.controller.netconf.api.NetconfSession;
 import org.opendaylight.controller.netconf.util.handler.FramingMechanismHandlerFactory;
-import org.opendaylight.controller.netconf.util.handler.NetconfHandlerFactory;
+import org.opendaylight.controller.netconf.util.handler.NetconfHelloMessageToXMLEncoder;
 import org.opendaylight.controller.netconf.util.handler.NetconfMessageAggregator;
+import org.opendaylight.controller.netconf.util.handler.NetconfXMLToHelloMessageDecoder;
 import org.opendaylight.controller.netconf.util.messages.FramingMechanism;
-import org.opendaylight.controller.netconf.util.messages.NetconfMessageFactory;
 
-public abstract class AbstractChannelInitializer {
+public abstract class AbstractChannelInitializer<S extends NetconfSession> {
+
+    public static final String NETCONF_MESSAGE_DECODER = "netconfMessageDecoder";
+    public static final String NETCONF_MESSAGE_AGGREGATOR = "aggregator";
+    public static final String NETCONF_MESSAGE_ENCODER = "netconfMessageEncoder";
+    public static final String NETCONF_MESSAGE_FRAME_ENCODER = "frameEncoder";
+    public static final String NETCONF_SESSION_NEGOTIATOR = "negotiator";
+
+    public void initialize(SocketChannel ch, Promise<S> promise) {
+        ch.pipeline().addLast(NETCONF_MESSAGE_AGGREGATOR, new NetconfMessageAggregator(FramingMechanism.EOM));
+        initializeMessageDecoder(ch);
+        ch.pipeline().addLast(NETCONF_MESSAGE_FRAME_ENCODER, FramingMechanismHandlerFactory.createHandler(FramingMechanism.EOM));
+        initializeMessageEncoder(ch);
+
+        initializeSessionNegotiator(ch, promise);
+    }
+
+    protected void initializeMessageEncoder(SocketChannel ch) {
+        // Special encoding handler for hello message to include additional header if available,
+        // it is thrown away after successful negotiation
+        ch.pipeline().addLast(NETCONF_MESSAGE_ENCODER, new NetconfHelloMessageToXMLEncoder());
+    }
 
-    public void initialize(SocketChannel ch, Promise<? extends NetconfSession> promise){
-        NetconfHandlerFactory handlerFactory = new NetconfHandlerFactory(new NetconfMessageFactory());
-        ch.pipeline().addLast("aggregator", new NetconfMessageAggregator(FramingMechanism.EOM));
-        ch.pipeline().addLast(handlerFactory.getDecoders());
-        initializeAfterDecoder(ch, promise);
-        ch.pipeline().addLast("frameEncoder", FramingMechanismHandlerFactory.createHandler(FramingMechanism.EOM));
-        ch.pipeline().addLast(handlerFactory.getEncoders());
+    protected void initializeMessageDecoder(SocketChannel ch) {
+        // Special decoding handler for hello message to parse additional header if available,
+        // it is thrown away after successful negotiation
+        ch.pipeline().addLast(NETCONF_MESSAGE_DECODER, new NetconfXMLToHelloMessageDecoder());
     }
 
-    protected abstract void initializeAfterDecoder(SocketChannel ch, Promise<? extends NetconfSession> promise);
+    /**
+     * Insert session negotiator into the pipeline. It must be inserted after message decoder
+     * identified by {@link AbstractChannelInitializer#NETCONF_MESSAGE_DECODER}, (or any other custom decoder processor)
+     */
+    protected abstract void initializeSessionNegotiator(SocketChannel ch, Promise<S> promise);
 
 }
index 8cfd177fceff03dad3cd1609d11152f30e55811a..9986b82bd8d6902a084e77a1a11a6421125ccb17 100644 (file)
@@ -8,46 +8,50 @@
 
 package org.opendaylight.controller.netconf.util;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import io.netty.channel.Channel;
-import io.netty.channel.ChannelHandler;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.ssl.SslHandler;
-import io.netty.util.Timeout;
-import io.netty.util.Timer;
-import io.netty.util.TimerTask;
-import io.netty.util.concurrent.Future;
-import io.netty.util.concurrent.GenericFutureListener;
-import io.netty.util.concurrent.Promise;
+import java.util.concurrent.TimeUnit;
+
+import org.opendaylight.controller.netconf.api.AbstractNetconfSession;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.api.NetconfSession;
+import org.opendaylight.controller.netconf.api.NetconfSessionListener;
 import org.opendaylight.controller.netconf.api.NetconfSessionPreferences;
 import org.opendaylight.controller.netconf.util.handler.FramingMechanismHandlerFactory;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
 import org.opendaylight.controller.netconf.util.handler.NetconfMessageAggregator;
 import org.opendaylight.controller.netconf.util.handler.NetconfMessageChunkDecoder;
+import org.opendaylight.controller.netconf.util.handler.NetconfMessageToXMLEncoder;
+import org.opendaylight.controller.netconf.util.handler.NetconfXMLToMessageDecoder;
 import org.opendaylight.controller.netconf.util.messages.FramingMechanism;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.opendaylight.protocol.framework.AbstractSessionNegotiator;
-import org.opendaylight.protocol.framework.SessionListener;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 import org.w3c.dom.NodeList;
 
-import java.util.concurrent.TimeUnit;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.ssl.SslHandler;
+import io.netty.util.Timeout;
+import io.netty.util.Timer;
+import io.netty.util.TimerTask;
+import io.netty.util.concurrent.Future;
+import io.netty.util.concurrent.GenericFutureListener;
+import io.netty.util.concurrent.Promise;
 
-public abstract class AbstractNetconfSessionNegotiator<P extends NetconfSessionPreferences, S extends NetconfSession>
-        extends AbstractSessionNegotiator<NetconfMessage, S> {
+public abstract class AbstractNetconfSessionNegotiator<P extends NetconfSessionPreferences, S extends AbstractNetconfSession<S, L>, L extends NetconfSessionListener<S>>
+extends AbstractSessionNegotiator<NetconfHelloMessage, S> {
 
     private static final Logger logger = LoggerFactory.getLogger(AbstractNetconfSessionNegotiator.class);
     public static final String NAME_OF_EXCEPTION_HANDLER = "lastExceptionHandler";
+    public static final String CHUNK_DECODER_CHANNEL_HANDLER_KEY = "chunkDecoder";
 
     protected final P sessionPreferences;
 
-    private final SessionListener sessionListener;
+    private final L sessionListener;
     private Timeout timeout;
 
     /**
@@ -62,7 +66,7 @@ public abstract class AbstractNetconfSessionNegotiator<P extends NetconfSessionP
     private final long connectionTimeoutMillis;
 
     protected AbstractNetconfSessionNegotiator(P sessionPreferences, Promise<S> promise, Channel channel, Timer timer,
-            SessionListener sessionListener, long connectionTimeoutMillis) {
+            L sessionListener, long connectionTimeoutMillis) {
         super(promise, channel);
         this.sessionPreferences = sessionPreferences;
         this.timer = timer;
@@ -119,7 +123,7 @@ public abstract class AbstractNetconfSessionNegotiator<P extends NetconfSessionP
             public void run(final Timeout timeout) throws Exception {
                 synchronized (this) {
                     if (state != State.ESTABLISHED) {
-                        logger.debug("Connection timeout after {}", timeout);
+                        logger.debug("Connection timeout after {}, session is in state {}", timeout, state);
                         final IllegalStateException cause = new IllegalStateException(
                                 "Session was not established after " + timeout);
                         negotiationFailed(cause);
@@ -145,20 +149,21 @@ public abstract class AbstractNetconfSessionNegotiator<P extends NetconfSessionP
     }
 
     @Override
-    protected void handleMessage(NetconfMessage netconfMessage) {
+    protected void handleMessage(NetconfHelloMessage netconfMessage) {
         final Document doc = netconfMessage.getDocument();
 
-        if (isHelloMessage(doc)) {
-            if (containsBase11Capability(doc)
-                    && containsBase11Capability(sessionPreferences.getHelloMessage().getDocument())) {
-                channel.pipeline().replace("frameEncoder", "frameEncoder",
-                        FramingMechanismHandlerFactory.createHandler(FramingMechanism.CHUNK));
-                channel.pipeline().replace("aggregator", "aggregator",
-                        new NetconfMessageAggregator(FramingMechanism.CHUNK));
-                channel.pipeline().addAfter("aggregator", "chunkDecoder", new NetconfMessageChunkDecoder());
+        // Only Hello message should arrive during negotiation
+        if (netconfMessage instanceof NetconfHelloMessage) {
+
+            replaceHelloMessageHandlers();
+
+            if (shouldUseChunkFraming(doc)) {
+                insertChunkFramingToPipeline();
             }
+
             changeState(State.ESTABLISHED);
-            S session = getSession(sessionListener, channel, netconfMessage);
+            S session = getSession(sessionListener, channel, (NetconfHelloMessage)netconfMessage);
+
             negotiationSuccessful(session);
         } else {
             final IllegalStateException cause = new IllegalStateException(
@@ -168,20 +173,38 @@ public abstract class AbstractNetconfSessionNegotiator<P extends NetconfSessionP
         }
     }
 
-    protected abstract S getSession(SessionListener sessionListener, Channel channel, NetconfMessage message);
+    /**
+     * Insert chunk framing handlers into the pipeline
+     */
+    private void insertChunkFramingToPipeline() {
+        replaceChannelHandler(channel, AbstractChannelInitializer.NETCONF_MESSAGE_FRAME_ENCODER,
+                FramingMechanismHandlerFactory.createHandler(FramingMechanism.CHUNK));
+        replaceChannelHandler(channel, AbstractChannelInitializer.NETCONF_MESSAGE_AGGREGATOR,
+                new NetconfMessageAggregator(FramingMechanism.CHUNK));
+        channel.pipeline().addAfter(AbstractChannelInitializer.NETCONF_MESSAGE_AGGREGATOR,
+                CHUNK_DECODER_CHANNEL_HANDLER_KEY, new NetconfMessageChunkDecoder());
+    }
 
-    private boolean isHelloMessage(Document doc) {
-        try {
-            XmlElement.fromDomElementWithExpected(doc.getDocumentElement(), "hello",
-                    XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
+    private boolean shouldUseChunkFraming(Document doc) {
+        return containsBase11Capability(doc)
+                && containsBase11Capability(sessionPreferences.getHelloMessage().getDocument());
+    }
 
-        } catch (IllegalArgumentException | IllegalStateException e) {
-            return false;
-        }
-        return true;
+    /**
+     * Remove special handlers for hello message. Insert regular netconf xml message (en|de)coders.
+     */
+    private void replaceHelloMessageHandlers() {
+        replaceChannelHandler(channel, AbstractChannelInitializer.NETCONF_MESSAGE_DECODER, new NetconfXMLToMessageDecoder());
+        replaceChannelHandler(channel, AbstractChannelInitializer.NETCONF_MESSAGE_ENCODER, new NetconfMessageToXMLEncoder());
     }
 
-    private void changeState(final State newState) {
+    private static ChannelHandler replaceChannelHandler(Channel channel, String handlerKey, ChannelHandler decoder) {
+        return channel.pipeline().replace(handlerKey, handlerKey, decoder);
+    }
+
+    protected abstract S getSession(L sessionListener, Channel channel, NetconfHelloMessage message);
+
+    private synchronized void changeState(final State newState) {
         logger.debug("Changing state from : {} to : {}", state, newState);
         Preconditions.checkState(isStateChangePermitted(state, newState), "Cannot change state from %s to %s", state,
                 newState);
@@ -206,6 +229,7 @@ public abstract class AbstractNetconfSessionNegotiator<P extends NetconfSessionP
         if (state == State.OPEN_WAIT && newState == State.FAILED)
             return true;
 
+        logger.debug("Transition from {} to {} is not allowed", state, newState);
         return false;
     }
 }
diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfHandlerFactory.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfHandlerFactory.java
deleted file mode 100644 (file)
index d878c5e..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.netconf.util.handler;
-
-import io.netty.channel.ChannelHandler;
-import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.util.messages.NetconfMessageFactory;
-import org.opendaylight.protocol.framework.ProtocolHandlerFactory;
-import org.opendaylight.protocol.framework.ProtocolMessageDecoder;
-import org.opendaylight.protocol.framework.ProtocolMessageEncoder;
-
-public class NetconfHandlerFactory extends ProtocolHandlerFactory<NetconfMessage> {
-
-    public NetconfHandlerFactory(final NetconfMessageFactory msgFactory) {
-        super(msgFactory);
-    }
-
-    @Override
-    public ChannelHandler[] getEncoders() {
-        return new ChannelHandler[] { new ProtocolMessageEncoder(this.msgFactory) };
-    }
-
-    @Override
-    public ChannelHandler[] getDecoders() {
-        return new ChannelHandler[] { new ProtocolMessageDecoder(this.msgFactory) };
-    }
-
-}
diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfHelloMessageToXMLEncoder.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfHelloMessageToXMLEncoder.java
new file mode 100644 (file)
index 0000000..a87d175
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.netconf.util.handler;
+
+import java.nio.ByteBuffer;
+
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+
+/**
+ * Customized NetconfMessageToXMLEncoder that serializes additional header with
+ * session metadata along with
+ * {@link org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage}
+ * . Used by netconf clients to send information about the user, ip address,
+ * protocol etc.
+ * <p/>
+ * Hello message with header example:
+ * <p/>
+ *
+ * <pre>
+ * {@code
+ * [tomas;10.0.0.0/10000;tcp;1000;1000;;/home/tomas;;]
+ * <hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ * <capabilities>
+ * <capability>urn:ietf:params:netconf:base:1.0</capability>
+ * </capabilities>
+ * </hello>
+ * }
+ * </pre>
+ */
+public final class NetconfHelloMessageToXMLEncoder extends NetconfMessageToXMLEncoder {
+
+    @Override
+    protected ByteBuffer encodeMessage(NetconfMessage msg) {
+        Preconditions.checkState(msg instanceof NetconfHelloMessage, "Netconf message of type %s expected, was %s",
+                NetconfHelloMessage.class, msg.getClass());
+        Optional<NetconfHelloMessageAdditionalHeader> headerOptional = ((NetconfHelloMessage) msg)
+                .getAdditionalHeader();
+
+        // If additional header present, serialize it along with netconf hello
+        // message
+        if (headerOptional.isPresent()) {
+            byte[] bytesFromHeader = headerOptional.get().toFormattedString().getBytes(Charsets.UTF_8);
+            byte[] bytesFromMessage = xmlToString(msg.getDocument()).getBytes(Charsets.UTF_8);
+
+            ByteBuffer byteBuffer = ByteBuffer.allocate(bytesFromHeader.length + bytesFromMessage.length)
+                    .put(bytesFromHeader).put(bytesFromMessage);
+            byteBuffer.flip();
+            return byteBuffer;
+        }
+
+        return super.encodeMessage(msg);
+    }
+}
index 39182263b6cd9e0c1067d347ad5839efb06281bf..5c00b9b7153818082cd3b2303efec085e6619f30 100644 (file)
@@ -8,19 +8,19 @@
 
 package org.opendaylight.controller.netconf.util.handler;
 
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.ByteToMessageDecoder;
+
 import java.nio.charset.Charset;
 import java.util.List;
 
+import org.opendaylight.controller.netconf.api.NetconfDeserializerException;
 import org.opendaylight.controller.netconf.util.messages.NetconfMessageConstants;
-import org.opendaylight.protocol.framework.DeserializerException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.Unpooled;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.codec.ByteToMessageDecoder;
-
 public class NetconfMessageChunkDecoder extends ByteToMessageDecoder {
 
     private final static Logger logger = LoggerFactory.getLogger(NetconfMessageChunkDecoder.class);
@@ -40,7 +40,7 @@ public class NetconfMessageChunkDecoder extends ByteToMessageDecoder {
                     in.readBytes(byteBufMsg, chunkSize);
                     isParsed = false;
                 } else {
-                    throw new DeserializerException("Unable to parse chunked data or header.");
+                    throw new NetconfDeserializerException("Unable to parse chunked data or header.");
                 }
             } catch (Exception e) {
                 logger.error("Failed to decode chunked message.", e);
diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfMessageToXMLEncoder.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfMessageToXMLEncoder.java
new file mode 100644 (file)
index 0000000..df0f7ef
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.netconf.util.handler;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.MessageToByteEncoder;
+
+import java.nio.ByteBuffer;
+
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Comment;
+import org.w3c.dom.Document;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Charsets;
+import com.google.common.base.Optional;
+
+public class NetconfMessageToXMLEncoder extends MessageToByteEncoder<NetconfMessage> {
+    private static final Logger LOG = LoggerFactory.getLogger(NetconfMessageToXMLEncoder.class);
+
+    private final Optional<String> clientId;
+
+    public NetconfMessageToXMLEncoder() {
+        this(Optional.<String>absent());
+    }
+
+    public NetconfMessageToXMLEncoder(Optional<String> clientId) {
+        this.clientId = clientId;
+    }
+
+    @Override
+    @VisibleForTesting
+    public void encode(ChannelHandlerContext ctx, NetconfMessage msg, ByteBuf out) throws Exception {
+        LOG.debug("Sent to encode : {}", msg);
+
+        if (clientId.isPresent()) {
+            Comment comment = msg.getDocument().createComment("clientId:" + clientId.get());
+            msg.getDocument().appendChild(comment);
+        }
+
+        final ByteBuffer msgBytes = encodeMessage(msg);
+
+        LOG.trace("Putting message \n{}", xmlToString(msg.getDocument()));
+        out.writeBytes(msgBytes);
+    }
+
+    protected ByteBuffer encodeMessage(NetconfMessage msg) {
+        return Charsets.UTF_8.encode(xmlToString(msg.getDocument()));
+    }
+
+    protected String xmlToString(Document doc) {
+        return XmlUtil.toString(doc, false);
+    }
+}
diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfXMLToHelloMessageDecoder.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfXMLToHelloMessageDecoder.java
new file mode 100644 (file)
index 0000000..42586a5
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.netconf.util.handler;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.List;
+
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
+import org.w3c.dom.Document;
+
+import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Customized NetconfXMLToMessageDecoder that reads additional header with
+ * session metadata from
+ * {@link org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage}
+ * . Used by netconf server to retrieve information about session metadata.
+ */
+public class NetconfXMLToHelloMessageDecoder extends NetconfXMLToMessageDecoder {
+
+    private static final List<byte[]> POSSIBLE_ENDS = ImmutableList.of(
+            new byte[] { ']', '\n' },
+            new byte[] { ']', '\r', '\n' });
+    private static final List<byte[]> POSSIBLE_STARTS = ImmutableList.of(
+            new byte[] { '[' },
+            new byte[] { '\r', '\n', '[' },
+            new byte[] { '\n', '[' });
+
+    private String additionalHeaderCache;
+
+    @Override
+    protected byte[] preprocessMessageBytes(byte[] bytes) {
+        // Extract bytes containing header with additional metadata
+
+        if (startsWithAdditionalHeader(bytes)) {
+            // Auth information containing username, ip address... extracted for monitoring
+            int endOfAuthHeader = getAdditionalHeaderEndIndex(bytes);
+            if (endOfAuthHeader > -1) {
+                byte[] additionalHeaderBytes = Arrays.copyOfRange(bytes, 0, endOfAuthHeader + 2);
+                additionalHeaderCache = additionalHeaderToString(additionalHeaderBytes);
+                bytes = Arrays.copyOfRange(bytes, endOfAuthHeader + 2, bytes.length);
+            }
+        }
+
+        return bytes;
+    }
+
+    @Override
+    protected void cleanUpAfterDecode() {
+        additionalHeaderCache = null;
+    }
+
+    @Override
+    protected NetconfMessage buildNetconfMessage(Document doc) {
+        return new NetconfHelloMessage(doc, additionalHeaderCache == null ? null
+                : NetconfHelloMessageAdditionalHeader.fromString(additionalHeaderCache));
+    }
+
+    private int getAdditionalHeaderEndIndex(byte[] bytes) {
+        for (byte[] possibleEnd : POSSIBLE_ENDS) {
+            int idx = findByteSequence(bytes, possibleEnd);
+
+            if (idx != -1) {
+                return idx;
+            }
+        }
+
+        return -1;
+    }
+
+    private static int findByteSequence(final byte[] bytes, final byte[] sequence) {
+        if (bytes.length < sequence.length) {
+            throw new IllegalArgumentException("Sequence to be found is longer than the given byte array.");
+        }
+        if (bytes.length == sequence.length) {
+            if (Arrays.equals(bytes, sequence)) {
+                return 0;
+            } else {
+                return -1;
+            }
+        }
+        int j = 0;
+        for (int i = 0; i < bytes.length; i++) {
+            if (bytes[i] == sequence[j]) {
+                j++;
+                if (j == sequence.length) {
+                    return i - j + 1;
+                }
+            } else {
+                j = 0;
+            }
+        }
+        return -1;
+    }
+
+    private boolean startsWithAdditionalHeader(byte[] bytes) {
+        for (byte[] possibleStart : POSSIBLE_STARTS) {
+            int i = 0;
+            for (byte b : possibleStart) {
+                if(bytes[i++] != b)
+                    break;
+
+                if(i == possibleStart.length)
+                    return true;
+            }
+        }
+
+        return false;
+    }
+
+    private String additionalHeaderToString(byte[] bytes) {
+        return Charsets.UTF_8.decode(ByteBuffer.wrap(bytes)).toString();
+    }
+
+}
diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfXMLToMessageDecoder.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfXMLToMessageDecoder.java
new file mode 100644 (file)
index 0000000..b697edf
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.netconf.util.handler;
+
+import java.io.ByteArrayInputStream;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import org.opendaylight.controller.netconf.api.NetconfDeserializerException;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Charsets;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.ByteBufUtil;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.ByteToMessageDecoder;
+
+public class NetconfXMLToMessageDecoder extends ByteToMessageDecoder {
+    private static final Logger LOG = LoggerFactory.getLogger(NetconfXMLToMessageDecoder.class);
+
+    @Override
+    @VisibleForTesting
+    public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
+        if (in.readableBytes() == 0) {
+            LOG.debug("No more content in incoming buffer.");
+            return;
+        }
+
+        in.markReaderIndex();
+        try {
+            LOG.trace("Received to decode: {}", ByteBufUtil.hexDump(in));
+            byte[] bytes = new byte[in.readableBytes()];
+            in.readBytes(bytes);
+
+            logMessage(bytes);
+
+            bytes = preprocessMessageBytes(bytes);
+            NetconfMessage message;
+            try {
+                Document doc = XmlUtil.readXmlToDocument(new ByteArrayInputStream(bytes));
+                message = buildNetconfMessage(doc);
+            } catch (Exception e) {
+                throw new NetconfDeserializerException("Could not parse message from " + new String(bytes), e);
+            }
+
+            out.add(message);
+        } finally {
+            in.discardReadBytes();
+            cleanUpAfterDecode();
+        }
+    }
+
+    protected void cleanUpAfterDecode() {}
+
+    protected NetconfMessage buildNetconfMessage(Document doc) {
+        return new NetconfMessage(doc);
+    }
+
+    protected byte[] preprocessMessageBytes(byte[] bytes) {
+        return bytes;
+    }
+
+    private void logMessage(byte[] bytes) {
+        String s = Charsets.UTF_8.decode(ByteBuffer.wrap(bytes)).toString();
+        LOG.debug("Parsing message \n{}", s);
+    }
+
+}
index 46fdbb83e77dceb02163478fa00f0c9391660f0f..5907ea8f136512c2028c3d79cc6dc64d4d8d4e33 100644 (file)
@@ -12,4 +12,5 @@ package org.opendaylight.controller.netconf.util.handler.ssh.virtualsocket;
  * Exception class which provides notification about exceptional situations at the virtual socket layer.
  */
 public class VirtualSocketException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
 }
index 86081b7f81d0f342669fdb1c7124b74dbff3157b..ba6364662cc5aae73bd0701e5084d263221c4575 100644 (file)
@@ -8,6 +8,8 @@
 
 package org.opendaylight.controller.netconf.util.mapping;
 
+import java.util.Map;
+
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
 import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
@@ -20,8 +22,6 @@ import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.NodeList;
 
-import java.util.Map;
-
 public abstract class AbstractNetconfOperation implements NetconfOperation {
     private final String netconfSessionIdForReporting;
 
@@ -29,7 +29,7 @@ public abstract class AbstractNetconfOperation implements NetconfOperation {
         this.netconfSessionIdForReporting = netconfSessionIdForReporting;
     }
 
-    public String getNetconfSessionIdForReporting() {
+    public final String getNetconfSessionIdForReporting() {
         return netconfSessionIdForReporting;
     }
 
@@ -67,7 +67,7 @@ public abstract class AbstractNetconfOperation implements NetconfOperation {
     protected abstract HandlingPriority canHandle(String operationName, String netconfOperationNamespace);
 
     @Override
-    public Document handle(Document message, NetconfOperationRouter opRouter) throws NetconfDocumentedException {
+    public final Document handle(Document message, NetconfOperationRouter opRouter) throws NetconfDocumentedException {
 
         XmlElement requestElement = getRequestElementWithCheck(message);
 
diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessage.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessage.java
new file mode 100644 (file)
index 0000000..249f894
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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.util.messages;
+
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.w3c.dom.Document;
+
+import com.google.common.base.Optional;
+
+/**
+ * NetconfMessage that can carry additional header with session metadata. See {@link org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader}
+ */
+public final class NetconfHelloMessage extends NetconfMessage {
+
+    public static final String HELLO_TAG = "hello";
+
+    private final NetconfHelloMessageAdditionalHeader additionalHeader;
+
+    public NetconfHelloMessage(Document doc, NetconfHelloMessageAdditionalHeader additionalHeader) {
+        super(doc);
+        checkHelloMessage(doc);
+        this.additionalHeader = additionalHeader;
+    }
+
+    public NetconfHelloMessage(Document doc) {
+        this(doc, null);
+    }
+
+    public Optional<NetconfHelloMessageAdditionalHeader> getAdditionalHeader() {
+        return additionalHeader== null ? Optional.<NetconfHelloMessageAdditionalHeader>absent() : Optional.of(additionalHeader);
+    }
+
+    private static void checkHelloMessage(Document doc) {
+        try {
+            XmlElement.fromDomElementWithExpected(doc.getDocumentElement(), HELLO_TAG,
+                    XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);
+
+        } catch (IllegalArgumentException | IllegalStateException e) {
+            throw new IllegalArgumentException(String.format(
+                    "Hello message invalid format, should contain %s tag from namespace %s, but is: %s", HELLO_TAG,
+                    XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, XmlUtil.toString(doc)), e);
+        }
+    }
+}
diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessageAdditionalHeader.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessageAdditionalHeader.java
new file mode 100644 (file)
index 0000000..f3ca30d
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * 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.util.messages;
+
+import com.google.common.base.Preconditions;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Additional header can be used with hello message to carry information about
+ * session's connection. Provided information can be reported via netconf
+ * monitoring.
+ * <pre>
+ * It has pattern "[username; host-address:port; transport; session-identifier;]"
+ * username - name of account on a remote
+ * host-address - client's IP address
+ * port - port number
+ * transport - tcp, ssh
+ * session-identifier - persister, client
+ * Session-identifier is optional, others mandatory.
+ * </pre>
+ * This header is inserted in front of a netconf hello message followed by a newline.
+ */
+public class NetconfHelloMessageAdditionalHeader {
+
+    private static final String SC = ";";
+
+    private final String userName;
+    private final String hostAddress;
+    private final String port;
+    private final String transport;
+    private final String sessionIdentifier;
+
+    public NetconfHelloMessageAdditionalHeader(String userName, String hostAddress, String port, String transport, String sessionIdentifier) {
+        this.userName = userName;
+        this.hostAddress = hostAddress;
+        this.port = port;
+        this.transport = transport;
+        this.sessionIdentifier = sessionIdentifier;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public String getAddress() {
+        return hostAddress;
+    }
+
+    public String getPort() {
+        return port;
+    }
+
+    public String getTransport() {
+        return transport;
+    }
+
+    public String getSessionIdentifier() {
+        return sessionIdentifier;
+    }
+
+    /**
+     * Format additional header into a string suitable as a prefix for netconf hello message
+     */
+    public String toFormattedString() {
+        Preconditions.checkNotNull(userName);
+        Preconditions.checkNotNull(hostAddress);
+        Preconditions.checkNotNull(port);
+        Preconditions.checkNotNull(transport);
+        Preconditions.checkNotNull(sessionIdentifier);
+        return "[" + userName + SC + hostAddress + ":" + port + SC + transport + SC + sessionIdentifier + SC + "]"
+                + System.lineSeparator();
+    }
+
+    @Override
+    public String toString() {
+        final StringBuffer sb = new StringBuffer("NetconfHelloMessageAdditionalHeader{");
+        sb.append("userName='").append(userName).append('\'');
+        sb.append(", hostAddress='").append(hostAddress).append('\'');
+        sb.append(", port='").append(port).append('\'');
+        sb.append(", transport='").append(transport).append('\'');
+        sb.append(", sessionIdentifier='").append(sessionIdentifier).append('\'');
+        sb.append('}');
+        return sb.toString();
+    }
+
+    // TODO IPv6
+    private static final Pattern pattern = Pattern
+            .compile("\\[(?<username>[^;]+);(?<address>[0-9\\.]+)[:/](?<port>[0-9]+);(?<transport>[a-z]+)[^\\]]+\\]");
+    private static final Pattern customHeaderPattern = Pattern
+            .compile("\\[(?<username>[^;]+);(?<address>[0-9\\.]+)[:/](?<port>[0-9]+);(?<transport>[a-z]+);(?<sessionIdentifier>[a-z]+)[^\\]]+\\]");
+
+    /**
+     * Parse additional header from a formatted string
+     */
+    public static NetconfHelloMessageAdditionalHeader fromString(String additionalHeader) {
+        additionalHeader = additionalHeader.trim();
+        Matcher matcher = pattern.matcher(additionalHeader);
+        Matcher matcher2 = customHeaderPattern.matcher(additionalHeader);
+        Preconditions.checkArgument(matcher.matches(), "Additional header in wrong format %s, expected %s",
+                additionalHeader, pattern);
+
+        String username = matcher.group("username");
+        String address = matcher.group("address");
+        String port = matcher.group("port");
+        String transport = matcher.group("transport");
+        String sessionIdentifier = "client";
+        if (matcher2.matches()) {
+            sessionIdentifier = matcher2.group("sessionIdentifier");
+        }
+        return new NetconfHelloMessageAdditionalHeader(username, address, port, transport, sessionIdentifier);
+    }
+
+}
diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageAdditionalHeader.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageAdditionalHeader.java
deleted file mode 100644 (file)
index 457e226..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.util.messages;
-
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-
-/**
- * Additional header can be used with hello message to carry information about
- * session's connection. Provided information can be reported via netconf
- * monitoring.
- * <pre>
- * It has pattern "[username; host-address:port; transport; session-identifier;]"
- * username - name of account on a remote
- * host-address - client's IP address
- * port - port number
- * transport - tcp, ssh
- * session-identifier - persister, client
- * Session-identifier is optional, others mandatory.
- * </pre>
- */
-public class NetconfMessageAdditionalHeader {
-
-    private static final String SC = ";";
-
-    public static String toString(String userName, String hostAddress, String port, String transport,
-            Optional<String> sessionIdentifier) {
-        Preconditions.checkNotNull(userName);
-        Preconditions.checkNotNull(hostAddress);
-        Preconditions.checkNotNull(port);
-        Preconditions.checkNotNull(transport);
-        String identifier = sessionIdentifier.isPresent() ? sessionIdentifier.get() : "";
-        return "[" + userName + SC + hostAddress + ":" + port + SC + transport + SC + identifier + SC + "]"
-                + System.lineSeparator();
-    }
-}
diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactory.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactory.java
deleted file mode 100644 (file)
index 6f86cc3..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.netconf.util.messages;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.List;
-
-import org.opendaylight.controller.netconf.api.NetconfDeserializerException;
-import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-import org.opendaylight.protocol.framework.DeserializerException;
-import org.opendaylight.protocol.framework.DocumentedException;
-import org.opendaylight.protocol.framework.ProtocolMessageFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.w3c.dom.Comment;
-import org.w3c.dom.Document;
-import org.xml.sax.SAXException;
-
-import com.google.common.base.Charsets;
-import com.google.common.base.Optional;
-import com.google.common.collect.ImmutableList;
-
-/**
- * NetconfMessageFactory for (de)serializing DOM documents.
- */
-public final class NetconfMessageFactory implements ProtocolMessageFactory<NetconfMessage> {
-
-    private static final Logger logger = LoggerFactory.getLogger(NetconfMessageFactory.class);
-    private static final List<byte[]> POSSIBLE_STARTS = ImmutableList.of(
-        "[".getBytes(Charsets.UTF_8), "\r\n[".getBytes(Charsets.UTF_8), "\n[".getBytes(Charsets.UTF_8));
-    private static final List<byte[]> POSSIBLE_ENDS = ImmutableList.of(
-        "]\n".getBytes(Charsets.UTF_8), "]\r\n".getBytes(Charsets.UTF_8));
-
-    private final Optional<String> clientId;
-
-    public NetconfMessageFactory() {
-        clientId = Optional.absent();
-    }
-
-    public NetconfMessageFactory(Optional<String> clientId) {
-        this.clientId = clientId;
-    }
-
-    @Override
-    public NetconfMessage parse(byte[] bytes) throws DeserializerException, DocumentedException {
-        logMessage(bytes);
-
-        String additionalHeader = null;
-
-        if (startsWithAdditionalHeader(bytes)) {
-            // Auth information containing username, ip address... extracted for monitoring
-            int endOfAuthHeader = getAdditionalHeaderEndIndex(bytes);
-            if (endOfAuthHeader > -1) {
-                byte[] additionalHeaderBytes = Arrays.copyOfRange(bytes, 0, endOfAuthHeader + 2);
-                additionalHeader = additionalHeaderToString(additionalHeaderBytes);
-                bytes = Arrays.copyOfRange(bytes, endOfAuthHeader + 2, bytes.length);
-            }
-        }
-        NetconfMessage message;
-        try {
-            Document doc = XmlUtil.readXmlToDocument(new ByteArrayInputStream(bytes));
-            message = new NetconfMessage(doc, additionalHeader);
-        } catch (final SAXException | IOException | IllegalStateException e) {
-            throw new NetconfDeserializerException("Could not parse message from " + new String(bytes), e);
-        }
-        return message;
-    }
-
-    private static int findByteSequence(final byte[] bytes, final byte[] sequence) {
-        if (bytes.length < sequence.length) {
-            throw new IllegalArgumentException("Sequence to be found is longer than the given byte array.");
-        }
-        if (bytes.length == sequence.length) {
-            if (Arrays.equals(bytes, sequence)) {
-                return 0;
-            } else {
-                return -1;
-            }
-        }
-        int j = 0;
-        for (int i = 0; i < bytes.length; i++) {
-            if (bytes[i] == sequence[j]) {
-                j++;
-                if (j == sequence.length) {
-                    return i - j + 1;
-                }
-            } else {
-                j = 0;
-            }
-        }
-        return -1;
-    }
-
-    private int getAdditionalHeaderEndIndex(byte[] bytes) {
-        for (byte[] possibleEnd : POSSIBLE_ENDS) {
-            int idx = findByteSequence(bytes, possibleEnd);
-
-            if (idx != -1) {
-                return idx;
-            }
-        }
-
-        return -1;
-    }
-
-    private boolean startsWithAdditionalHeader(byte[] bytes) {
-        for (byte[] possibleStart : POSSIBLE_STARTS) {
-            int i = 0;
-            for (byte b : possibleStart) {
-                if(bytes[i] != b)
-                    break;
-
-                return true;
-            }
-        }
-
-        return false;
-    };
-
-    private void logMessage(byte[] bytes) {
-        String s = Charsets.UTF_8.decode(ByteBuffer.wrap(bytes)).toString();
-        logger.debug("Parsing message \n{}", s);
-    }
-
-    private String additionalHeaderToString(byte[] bytes) {
-        return Charsets.UTF_8.decode(ByteBuffer.wrap(bytes)).toString();
-    }
-
-    @Override
-    public byte[] put(NetconfMessage netconfMessage) {
-        if (clientId.isPresent()) {
-            Comment comment = netconfMessage.getDocument().createComment("clientId:" + clientId.get());
-            netconfMessage.getDocument().appendChild(comment);
-        }
-        ByteBuffer msgBytes;
-        if(netconfMessage.getAdditionalHeader().isPresent()) {
-            String header = netconfMessage.getAdditionalHeader().get();
-            logger.trace("Header of netconf message parsed \n{}", header);
-            msgBytes = Charsets.UTF_8.encode(header + xmlToString(netconfMessage.getDocument()));
-        } else {
-            msgBytes = Charsets.UTF_8.encode(xmlToString(netconfMessage.getDocument()));
-        }
-        String content = xmlToString(netconfMessage.getDocument());
-
-        logger.trace("Putting message \n{}", content);
-        byte[] b = new byte[msgBytes.limit()];
-        msgBytes.get(b);
-        return b;
-    }
-
-    private String xmlToString(Document doc) {
-        return XmlUtil.toString(doc, false);
-    }
-}
index f8c90836b977ab832bfb6b735df2e7f6d1de0b39..6b7bffcd862394c678b1dfa69e65bbaad9481f89 100644 (file)
@@ -7,19 +7,27 @@
  */
 package org.opendaylight.controller.netconf.util.messages;
 
-import com.google.common.io.Files;
-import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import io.netty.buffer.Unpooled;
 
 import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
 
-public class NetconfMessageFactoryTest {
+import org.junit.Test;
+import org.opendaylight.controller.netconf.util.handler.NetconfXMLToHelloMessageDecoder;
+import org.opendaylight.controller.netconf.util.handler.NetconfXMLToMessageDecoder;
 
+import com.google.common.io.Files;
 
+public class NetconfMessageFactoryTest {
     @Test
     public void testAuth() throws Exception {
-        NetconfMessageFactory parser = new NetconfMessageFactory();
+        NetconfXMLToMessageDecoder parser = new NetconfXMLToHelloMessageDecoder();
         File authHelloFile = new File(getClass().getResource("/netconfMessages/client_hello_with_auth.xml").getFile());
-        parser.parse(Files.toByteArray(authHelloFile));
 
+        final List<Object> out = new ArrayList<>();
+        parser.decode(null, Unpooled.wrappedBuffer(Files.toByteArray(authHelloFile)), out);
+        assertEquals(1, out.size());
     }
 }
index 83e251aed8c3e1d9d56d6e091b4fa9902cee5072..821ac92021683e8d0cccdd6409b28f09add1ad0d 100644 (file)
@@ -34,7 +34,6 @@
       <url>${sitedeploy}</url>
     </site>
   </distributionManagement>
-  <groupId>org.opendaylight.controller</groupId>
   <artifactId>networkconfig.neutron.implementation</artifactId>
   <version>0.4.2-SNAPSHOT</version>
   <packaging>bundle</packaging>
index fc728dc89f4162ef58487e7ca94f2bd7a2cf6d17..27588b8bee907b8015df57daa5140d77d935dd8a 100644 (file)
@@ -33,7 +33,6 @@
       <url>${sitedeploy}</url>
     </site>
   </distributionManagement>
-  <groupId>org.opendaylight.controller</groupId>
   <artifactId>networkconfig.neutron</artifactId>
   <version>0.4.2-SNAPSHOT</version>
   <packaging>bundle</packaging>
index 11a1be21180db9f454cc1817ed55f762429d904d..6582d8c021d5f61de10ae6b221f1217fdd1d668f 100644 (file)
@@ -269,22 +269,26 @@ public class NeutronSubnet extends ConfigurationObject implements Serializable {
         }
         gatewayIPAssigned = false;
         dnsNameservers = new ArrayList<String>();
-        allocationPools = new ArrayList<NeutronSubnet_IPAllocationPool>();
-        hostRoutes = new ArrayList<NeutronSubnet_HostRoute>();
-        try {
-            SubnetUtils util = new SubnetUtils(cidr);
-            SubnetInfo info = util.getInfo();
-            if (gatewayIP == null) {
-                gatewayIP = info.getLowAddress();
-            }
-            if (allocationPools.size() < 1) {
-                NeutronSubnet_IPAllocationPool source =
-                    new NeutronSubnet_IPAllocationPool(info.getLowAddress(),
-                            info.getHighAddress());
-                allocationPools = source.splitPool(gatewayIP);
+        if (hostRoutes == null) {
+            hostRoutes = new ArrayList<NeutronSubnet_HostRoute>();
+        }
+        if (allocationPools == null) {
+            allocationPools = new ArrayList<NeutronSubnet_IPAllocationPool>();
+            try {
+                SubnetUtils util = new SubnetUtils(cidr);
+                SubnetInfo info = util.getInfo();
+                if (gatewayIP == null) {
+                    gatewayIP = info.getLowAddress();
+                }
+                if (allocationPools.size() < 1) {
+                    NeutronSubnet_IPAllocationPool source =
+                        new NeutronSubnet_IPAllocationPool(info.getLowAddress(),
+                                info.getHighAddress());
+                    allocationPools = source.splitPool(gatewayIP);
+                }
+            } catch (Exception e) {
+                return false;
             }
-        } catch (Exception e) {
-            return false;
         }
         return true;
     }
index 2d980910f4a90ada714a0a46929c7e3eeb17b2c6..48dee485ae7437e80c5e7deafa0f346759db57b8 100644 (file)
@@ -14,7 +14,6 @@
     <tag>HEAD</tag>
   </scm>
 
-  <groupId>org.opendaylight.controller</groupId>
   <artifactId>containermanager.northbound</artifactId>
   <version>0.4.2-SNAPSHOT</version>
   <packaging>bundle</packaging>
index a6b3855d1f0401e6cf7c7d66bc93124f740547b2..278952666819e6365c6f8479bdea91f827e245bf 100644 (file)
@@ -14,7 +14,6 @@
     <tag>HEAD</tag>
   </scm>
 
-  <groupId>org.opendaylight.controller</groupId>
   <artifactId>northbound.integrationtest</artifactId>
   <version>0.4.2-SNAPSHOT</version>
   <pluginRepositories>
index a6596f886d7e0e58fe57ed0d537bcd45a28ca6ba..7590a976b6fe6f2e0abcf35a1ca900a8967e3413 100644 (file)
@@ -34,7 +34,6 @@
             <url>${sitedeploy}</url>
         </site>
     </distributionManagement>
-    <groupId>org.opendaylight.controller</groupId>
     <artifactId>networkconfig.neutron.northbound</artifactId>
     <version>0.4.2-SNAPSHOT</version>
     <packaging>bundle</packaging>
index 642b3bb197c1e0e9416967cbc71760ef79c64ecf..c26e0229d0271ed6a6a0a10f0e17755176f69595 100644 (file)
@@ -60,6 +60,8 @@ import org.opendaylight.controller.sal.utils.ServiceHelper;
 @Path("/ports")
 public class NeutronPortsNorthbound {
 
+    final String mac_regex="^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$";
+
     private NeutronPort extractFields(NeutronPort o, List<String> fields) {
         return o.extractFields(fields);
     }
@@ -207,7 +209,7 @@ public class NeutronPortsNorthbound {
                 return Response.status(404).build();
             }
             if (singleton.getMacAddress() == null ||
-                    !singleton.getMacAddress().matches("^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$")) {
+                    !singleton.getMacAddress().matches(mac_regex)) {
                 return Response.status(400).build();
             }
             if (portInterface.macInUse(singleton.getMacAddress())) {
@@ -298,7 +300,7 @@ public class NeutronPortsNorthbound {
                 if (!networkInterface.networkExists(test.getNetworkUUID())) {
                     return Response.status(404).build();
                 }
-                if (!test.getMacAddress().matches("^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$")) {
+                if (!test.getMacAddress().matches(mac_regex)) {
                     return Response.status(400).build();
                 }
                 if (portInterface.macInUse(test.getMacAddress())) {
index 8eff06a763692a4774afe57c7b6a816a0a07d2f3..662af723ed4861aa339ff99c3cacedb00af20cf2 100644 (file)
@@ -416,7 +416,7 @@ public class SwitchNorthbound {
      *         {@link org.opendaylight.controller.sal.core.Property} attached to
      *         it.
      *
-     *         <pre>
+     * <pre>
      *
      * Example:
      *
@@ -540,8 +540,10 @@ public class SwitchNorthbound {
      *            Type of the node connector being programmed (Eg. 'OF')
      * @param nodeConnectorId
      *            NodeConnector Identifier as specified by
-     *            {@link org.opendaylight.controller.sal.core.NodeConnector}
-     *            (Eg. '2')
+     *            {@link org.opendaylight.controller.sal.core.NodeConnector}.
+     *            (Eg. '2'). If nodeConnecterId contains forward slash(/),
+     *            replace forward slash with underscore(_) in the URL. (Eg. for
+     *            Ethernet1/2, use Ethernet1_2)
      * @param propertyName
      *            Name of the Property specified by
      *            {@link org.opendaylight.controller.sal.core.Property} and its
@@ -552,7 +554,7 @@ public class SwitchNorthbound {
      *            extended classes
      * @return Response as dictated by the HTTP Response Status code
      *
-     *         <pre>
+     * <pre>
      *
      * Example:
      *
@@ -592,6 +594,10 @@ public class SwitchNorthbound {
         handleNodeAvailability(containerName, nodeType, nodeId);
         Node node = Node.fromString(nodeType, nodeId);
 
+        if (nodeConnectorId.contains("_")) {
+            nodeConnectorId = nodeConnectorId.replace("_", "/");
+        }
+
         handleNodeConnectorAvailability(containerName, node, nodeConnectorType, nodeConnectorId);
         NodeConnector nc = NodeConnector.fromStringNoNode(nodeConnectorType, nodeConnectorId, node);
 
@@ -625,14 +631,16 @@ public class SwitchNorthbound {
      * @param nodeConnectorId
      *            NodeConnector Identifier as specified by
      *            {@link org.opendaylight.controller.sal.core.NodeConnector}
-     *            (Eg. '1')
+     *            (Eg. '1'). If nodeConnecterId contains forward slash(/),
+     *            replace forward slash with underscore(_) in the URL. (Eg. for
+     *            Ethernet1/2, use Ethernet1_2)
      * @param propertyName
      *            Name of the Property specified by
      *            {@link org.opendaylight.controller.sal.core.Property} and its
      *            extended classes. Property that can be deleted is bandwidth
      * @return Response as dictated by the HTTP Response Status code
      *
-     *         <pre>
+     * <pre>
      *
      * Example:
      *
@@ -670,6 +678,10 @@ public class SwitchNorthbound {
         handleNodeAvailability(containerName, nodeType, nodeId);
         Node node = Node.fromString(nodeType, nodeId);
 
+        if (nodeConnectorId.contains("_")) {
+            nodeConnectorId = nodeConnectorId.replace("_", "/");
+        }
+
         handleNodeConnectorAvailability(containerName, node, nodeConnectorType, nodeConnectorId);
         NodeConnector nc = NodeConnector.fromStringNoNode(nodeConnectorType, nodeConnectorId, node);
         Status ret = switchManager.removeNodeConnectorProp(nc, propertyName);
index 72ee7a679b010400e342047278136e2c73aa3a09..63dd0bc29ae03daefe8444991c00190dd28f9e06 100644 (file)
@@ -48,6 +48,7 @@ public class Controller implements IController, CommandProvider, IPluginInConnec
             .getLogger(Controller.class);
     private ControllerIO controllerIO;
     private Thread switchEventThread;
+    private volatile boolean shutdownSwitchEventThread;// default to false
     private ConcurrentHashMap<Long, ISwitch> switches;
     private PriorityBlockingQueue<SwitchEvent> switchEvents;
     // only 1 message listener per OFType
@@ -69,6 +70,12 @@ public class Controller implements IController, CommandProvider, IPluginInConnec
 
             while (true) {
                 try {
+                    if(shutdownSwitchEventThread) {
+                        // break out of the infinite loop
+                        // if you are shutting down
+                        logger.info("Switch Event Thread is shutting down");
+                        break;
+                    }
                     SwitchEvent ev = switchEvents.take();
                     SwitchEvent.SwitchEventType eType = ev.getEventType();
                     ISwitch sw = ev.getSwitch();
@@ -104,12 +111,14 @@ public class Controller implements IController, CommandProvider, IPluginInConnec
                         logger.error("Unknown switch event {}", eType.ordinal());
                     }
                 } catch (InterruptedException e) {
-                    switchEvents.clear();
-                    return;
+                    // nothing to do except retry
+                } catch (Exception e) {
+                    // log the exception and retry
+                    logger.warn("Exception in Switch Event Thread is {}" ,e);
                 }
             }
+            switchEvents.clear();
         }
-
     }
 
     /**
@@ -167,6 +176,7 @@ public class Controller implements IController, CommandProvider, IPluginInConnec
             ((SwitchHandler) entry.getValue()).stop();
             it.remove();
         }
+        shutdownSwitchEventThread = true;
         switchEventThread.interrupt();
         try {
             controllerIO.shutDown();
index d60bcab8b32fdf299d68505c348fe5b4fc5ec831..aa60f9117405270725514dc740f564ad8e2ccd03 100644 (file)
@@ -407,9 +407,9 @@ public class SecureMessageReadWriteService implements IMessageReadWrite {
         this.myAppData = ByteBuffer
                 .allocate(session.getApplicationBufferSize());
         this.peerAppData = ByteBuffer.allocate(session
-                .getApplicationBufferSize() * 2);
+                .getApplicationBufferSize() * 20);
         this.myNetData = ByteBuffer.allocate(session.getPacketBufferSize());
-        this.peerNetData = ByteBuffer.allocate(session.getPacketBufferSize() * 2);
+        this.peerNetData = ByteBuffer.allocate(session.getPacketBufferSize() * 20);
     }
 
     @Override
index 394be07dee2968b838377d8424ad8c70d49f4bce..b29ce15f5621aa0c09b29bafdf080448b973b628 100644 (file)
@@ -391,7 +391,12 @@ public class DiscoveryService implements IInventoryShimExternalListener, IDataPa
 
             updateProdEdge(edge, props);
         } catch (Exception e) {
-            logger.warn("Caught exception ", e);
+            if (logger.isDebugEnabled()) {
+                logger.debug(
+                        "Caught exception while attempting to snoop non controller generated or malformed LLDP frame sent by {} and received on {}: {}",
+                        HexEncode.bytesToHexStringFormat(ethPkt.getSourceMACAddress()), dstNodeConnector,
+                        e.getMessage());
+            }
         }
     }
 
index 6c3424c616c46799908911e56e5323f8103d99cd..dc341625af642395872a3e2860a9d0fcc6f1ce3b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ * Copyright (c) 2013-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,
@@ -482,7 +482,7 @@ public abstract class NetUtils {
      * @return the int variable containing the unsigned byte value
      */
     public static int getUnsignedByte(byte b) {
-        return (b > 0) ? (int) b : (b & 0x7F | 0x80);
+        return b & 0xFF;
     }
 
     /**
@@ -493,7 +493,7 @@ public abstract class NetUtils {
      * @return the int variable containing the unsigned short value
      */
     public static int getUnsignedShort(short s) {
-        return (s > 0) ? (int) s : (s & 0x7FFF | 0x8000);
+        return s & 0xFFFF;
     }
 
     /**
@@ -520,5 +520,4 @@ public abstract class NetUtils {
     public static byte[] getBroadcastMACAddr() {
         return Arrays.copyOf(BroadcastMACAddr, BroadcastMACAddr.length);
     }
-
 }
index b8bc6fb4470901c0761df18e51482489c7e4325b..a2b12782ac2986f24cfd6fbe8f295f5ef105712d 100644 (file)
@@ -1,6 +1,5 @@
-
 /*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ * Copyright (c) 2013-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,
@@ -449,4 +448,24 @@ public class NetUtilsTest {
         Assert.assertTrue(NetUtils
                 .isIPAddressValid("2001:420:281:1004:407a:57f4:4d15:c355"));
     }
+
+    @Test
+    public void testGetUnsignedByte() {
+        Assert.assertEquals(0,   NetUtils.getUnsignedByte((byte) 0x00));
+        Assert.assertEquals(1,   NetUtils.getUnsignedByte((byte) 0x01));
+        Assert.assertEquals(127, NetUtils.getUnsignedByte((byte) 0x7f));
+
+        Assert.assertEquals(128, NetUtils.getUnsignedByte((byte) 0x80));
+        Assert.assertEquals(255, NetUtils.getUnsignedByte((byte) 0xff));
+    }
+
+    @Test
+    public void testGetUnsignedShort() {
+        Assert.assertEquals(0,     NetUtils.getUnsignedShort((short) 0x0000));
+        Assert.assertEquals(1,     NetUtils.getUnsignedShort((short) 0x0001));
+        Assert.assertEquals(32767, NetUtils.getUnsignedShort((short) 0x7fff));
+
+        Assert.assertEquals(32768, NetUtils.getUnsignedShort((short) 0x8000));
+        Assert.assertEquals(65535, NetUtils.getUnsignedShort((short) 0xffff));
+    }
 }
index fec6bbe6b466519f9c5e8ed3cc5d89aa2558b66e..d2016b1f6337b6923662268ae7d8029d34ae85b0 100644 (file)
@@ -48,7 +48,7 @@ public class SimpleBroadcastHandlerImpl implements IBroadcastHandler, IListenDat
 
     protected ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
 
-    BroadcastMode mode = BroadcastMode.BROADCAST_TO_NONINTERNAL;
+    BroadcastMode mode = BroadcastMode.DISABLED;
 
     @Override
     public PacketResult receiveDataPacket(RawPacket inPkt) {
index aa6e4ac383ee2be208ed8124c1c5248fa95f26dc..2376b8752f1e5d675277024cb98cdc4c25a77b0c 100644 (file)
@@ -314,9 +314,9 @@ public class StatisticsManager implements IStatisticsManager, IReadServiceListen
             try {
                 boolean retStatus;
                 if(oldLatch != null) {
-                    retStatus = oldLatch.await(this.latchTimeout, TimeUnit.SECONDS);
+                    retStatus = oldLatch.await(StatisticsManager.latchTimeout, TimeUnit.SECONDS);
                 } else {
-                    retStatus = newLatch.await(this.latchTimeout, TimeUnit.SECONDS);
+                    retStatus = newLatch.await(StatisticsManager.latchTimeout, TimeUnit.SECONDS);
                 }
                 // log the return code as it will give us, if
                 // the latch timed out.
@@ -467,11 +467,8 @@ public class StatisticsManager implements IStatisticsManager, IReadServiceListen
 
     @Override
     public void nodeFlowStatisticsUpdated(Node node, List<FlowOnNode> flowStatsList) {
-        List<FlowOnNode> currentStat = this.flowStatistics.get(node);
-        // Update cache only if changed to avoid unnecessary cache sync operations
-        if (! flowStatsList.equals(currentStat)){
-            this.flowStatistics.put(node, flowStatsList);
-        }
+        // No equality check because duration fields change constantly
+        this.flowStatistics.put(node, flowStatsList);
     }
 
     @Override
index 28c811c669f62418e836fd6ed3af0cb103e040c4..b8d022f30e76eae6df2b81021eb779e14704bf20 100644 (file)
@@ -21,7 +21,7 @@ import org.opendaylight.controller.sal.utils.Status;
 import org.opendaylight.controller.sal.utils.StatusCode;
 
 /**
- * The class describes a switch configuration
+ * The class describes a switch configuration as a collection of properties
  */
 public class SwitchConfig extends ConfigurationObject implements Cloneable, Serializable {
     private static final long serialVersionUID = 1L;
@@ -123,15 +123,20 @@ public class SwitchConfig extends ConfigurationObject implements Cloneable, Seri
     }
 
     private Status validateNodeId() {
-        if (nodeId == null || nodeId.isEmpty()) {
-            return new Status(StatusCode.BADREQUEST, "NodeId cannot be empty");
+        if (nodeId == null || nodeId.trim().isEmpty()) {
+            return new Status(StatusCode.BADREQUEST, "Invalid node id");
         }
         return new Status(StatusCode.SUCCESS);
     }
 
     private Status validateNodeProperties() {
         if (nodeProperties == null) {
-            return new Status(StatusCode.BADREQUEST, "nodeProperties cannot be null");
+            return new Status(StatusCode.BADREQUEST, "Node properties must be specified");
+        }
+        if (nodeProperties.containsKey(Description.propertyName)) {
+            if (!isValidResourceName(((Description)nodeProperties.get(Description.propertyName)).getValue())) {
+                return new Status(StatusCode.BADREQUEST, "Invalid node description");
+            }
         }
         return new Status(StatusCode.SUCCESS);
     }
index 19f45e63c591dbde396e0929141c5c042a55adf5..e457fecfedf9b75d5ec1f59f006d64775472e144 100644 (file)
@@ -1004,7 +1004,8 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
             }
         }
 
-        boolean proactiveForwarding = false;
+        boolean forwardingModeChanged = false;
+
         // copy node properties from config
         if (nodeConfigList != null) {
             String nodeId = node.toString();
@@ -1014,7 +1015,7 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
                 propMap.putAll(nodeProperties);
                 if (nodeProperties.get(ForwardingMode.name) != null) {
                     ForwardingMode mode = (ForwardingMode) nodeProperties.get(ForwardingMode.name);
-                    proactiveForwarding = mode.isProactive();
+                    forwardingModeChanged = mode.isProactive();
                 }
             }
         }
@@ -1023,28 +1024,35 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
             Property defaultMode = new ForwardingMode(ForwardingMode.REACTIVE_FORWARDING);
             propMap.put(ForwardingMode.name, defaultMode);
         }
-        boolean result = false;
-        if (propMapCurr == null) {
-            if (nodeProps.putIfAbsent(node, propMap) == null) {
-                result = true;
-            }
+
+        boolean propsAdded = false;
+        // Attempt initial add
+        if (nodeProps.putIfAbsent(node, propMap) == null) {
+                propsAdded = true;
+
+                /* Notify listeners only for initial node addition
+                 * to avoid expensive tasks triggered by redundant notifications
+                 */
+                notifyNode(node, UpdateType.ADDED, propMap);
         } else {
-            result = nodeProps.replace(node, propMapCurr, propMap);
+
+            propsAdded = nodeProps.replace(node, propMapCurr, propMap);
+
+            // check whether forwarding mode changed
+            if (propMapCurr.get(ForwardingMode.name) != null) {
+                ForwardingMode mode = (ForwardingMode) propMapCurr.get(ForwardingMode.name);
+                forwardingModeChanged ^= mode.isProactive();
+            }
         }
-        if (!result) {
-            log.debug("Cluster conflict: Conflict while adding the node properties. Node: {}  Properties: {}",
-                    node.getID(), props);
+        if (!propsAdded) {
+            log.debug("Cluster conflict while adding node {}. Overwriting with latest props: {}", node.getID(), props);
             addNodeProps(node, propMap);
         }
 
-        // check if span ports are configed
+        // check if span ports are configured
         addSpanPorts(node);
-
-        // notify node listeners
-        notifyNode(node, UpdateType.ADDED, propMap);
-
         // notify proactive mode forwarding
-        if (proactiveForwarding) {
+        if (forwardingModeChanged) {
             notifyModeChange(node, true);
         }
     }
@@ -1054,7 +1062,12 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
         if (nodeProps == null) {
             return;
         }
-        nodeProps.remove(node);
+
+        if (nodeProps.remove(node) == null) {
+            log.debug("Received redundant node REMOVED udate for {}. Skipping..", node);
+            return;
+        }
+
         nodeConnectorNames.remove(node);
         Set<NodeConnector> removeNodeConnectorSet = new HashSet<NodeConnector>();
         for (Map.Entry<NodeConnector, Map<String, Property>> entry : nodeConnectorProps.entrySet()) {
@@ -1149,6 +1162,13 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
 
         switch (type) {
         case ADDED:
+            // Skip redundant ADDED update (e.g. cluster switch-over)
+            if (nodeConnectorProps.containsKey(nodeConnector)) {
+                log.debug("Redundant nodeconnector ADDED for {}, props {} for container {}",
+                        nodeConnector, props, containerName);
+                update = false;
+            }
+
             if (props != null) {
                 for (Property prop : props) {
                     addNodeConnectorProp(nodeConnector, prop);
@@ -1158,6 +1178,7 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
                 addNodeConnectorProp(nodeConnector, null);
             }
 
+
             addSpanPort(nodeConnector);
             break;
         case CHANGED:
@@ -2026,9 +2047,9 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
         // only add if span is configured on this nodeConnector
         for (SpanConfig conf : getSpanConfigList(nodeConnector.getNode())) {
             if (conf.getPortArrayList().contains(nodeConnector)) {
-                List<NodeConnector> ncLists = new ArrayList<NodeConnector>();
-                ncLists.add(nodeConnector);
-                addSpanPorts(nodeConnector.getNode(), ncLists);
+                List<NodeConnector> ncList = new ArrayList<NodeConnector>();
+                ncList.add(nodeConnector);
+                addSpanPorts(nodeConnector.getNode(), ncList);
                 return;
             }
         }
@@ -2149,7 +2170,7 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
     public Set<Switch> getConfiguredNotConnectedSwitches() {
         Set<Switch> configuredNotConnectedSwitches = new HashSet<Switch>();
         if (this.inventoryService == null) {
-            log.trace("inventory service not avaiable");
+            log.trace("inventory service not available");
             return configuredNotConnectedSwitches;
         }
 
index 94200e66e077e440fe379711904ca5720dd130f4..809ca134f77cf4cb62e4517d152b0e8b9342f9cd 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.controller.usermanager;
 
 import java.io.Serializable;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 
@@ -47,7 +48,7 @@ public class AuthenticatedUser implements Serializable {
     }
 
     public List<String> getUserRoles() {
-        return userRoles;
+        return userRoles == null ? Collections.<String> emptyList() : new ArrayList<String>(userRoles);
     }
 
     public void addUserRole(String string) {
index b8a1a987694cfec72ae8898256cabe1e12e0fe7f..d32799e3eb7462fc223a1af458a179a5c3a3782d 100644 (file)
@@ -8,15 +8,15 @@
 
 package org.opendaylight.controller.usermanager;
 
+import java.util.Arrays;
+import java.util.List;
+
 import org.junit.Assert;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.opendaylight.controller.sal.authorization.UserLevel;
 import org.springframework.security.core.GrantedAuthority;
 
-import java.util.Arrays;
-import java.util.List;
-
 public class AuthenticatedUserTest {
 
         static String[] roleArray;
@@ -33,7 +33,7 @@ public class AuthenticatedUserTest {
                 user = new AuthenticatedUser("auser");
 
                 Assert.assertFalse(user.getAccessDate().isEmpty());
-                Assert.assertNull(user.getUserRoles());
+        Assert.assertNotNull(user.getUserRoles());
         }
 
         @Test
index 094562fac07252b182e601774e79209d0a473e20..ab8301bf73dd21fb842aeee16b3a80dc647039a2 100644 (file)
@@ -457,7 +457,8 @@ one.f.flows = {
             var editButton = one.lib.dashlet.button.single("Edit Flow", one.f.flows.id.dashlet.edit, "btn-primary", "btn-mini");
             var $editButton = one.lib.dashlet.button.button(editButton);
             $editButton.click(function() {
-                var $modal = one.f.flows.modal.initialize(true);
+               var install = flow['flow']['installInHw'];
+                var $modal = one.f.flows.modal.initialize(true,install);
                 $modal.modal().on('shown',function(){
                     var $port = $('#'+one.f.flows.id.modal.form.port);
                     $('#'+one.f.flows.id.modal.form.nodes).trigger("change");
@@ -550,7 +551,7 @@ one.f.flows = {
                 return $p;
             }
         },
-        initialize : function(edit) {
+        initialize : function(edit,install) {
             var h3;
             if(edit) {
                 h3 = "Edit Flow Entry";
@@ -571,7 +572,7 @@ one.f.flows = {
             if (edit) {
                 // bind edit flow button
                 $('#'+one.f.flows.id.modal.edit, $modal).click(function() {
-                    one.f.flows.modal.save($modal, 'true', true);
+                    one.f.flows.modal.save($modal, install, true);
                 });
             } else {
                 // bind add flow button
index 36b5043dd94ebf6956c499da4ad4909864a9c936..04fbf846b7e820b2f6deaa17f28d0286fc74367a 100644 (file)
@@ -41,6 +41,7 @@ import org.opendaylight.controller.sal.match.Match;
 import org.opendaylight.controller.sal.match.MatchType;
 import org.opendaylight.controller.sal.reader.FlowOnNode;
 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
+import org.opendaylight.controller.sal.reader.NodeDescription;
 import org.opendaylight.controller.sal.utils.EtherTypes;
 import org.opendaylight.controller.sal.utils.GlobalConstants;
 import org.opendaylight.controller.sal.utils.HexEncode;
@@ -101,6 +102,30 @@ public class Troubleshoot implements IDaylightWeb {
         return userLevel.ordinal() <= AUTH_LEVEL.ordinal();
     }
 
+    @RequestMapping(value = "/nodeInfo", method = RequestMethod.GET)
+    @ResponseBody
+    public NodeDescription getNodeInfo(HttpServletRequest request, @RequestParam(required = false) String container,
+            @RequestParam(required = true) String nodeId) {
+        List<Map<String, String>> lines = new ArrayList<Map<String, String>>();
+        String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
+
+        // Derive the privilege this user has on the current container
+        String userName = request.getUserPrincipal().getName();
+        Privilege privilege = DaylightWebUtil.getContainerPrivilege(userName, containerName, this);
+
+        if (privilege != Privilege.NONE) {
+            IStatisticsManager statisticsManager = (IStatisticsManager) ServiceHelper
+                    .getInstance(IStatisticsManager.class, containerName, this);
+            if(statisticsManager != null){
+                Node node = Node.fromString(nodeId);
+                NodeDescription nodeDesc = statisticsManager.getNodeDescription(node);
+                return nodeDesc;
+            }
+        }
+
+        return new NodeDescription();
+    }
+
     @RequestMapping(value = "/existingNodes", method = RequestMethod.GET)
     @ResponseBody
     public TroubleshootingJsonBean getExistingNodes(HttpServletRequest request, @RequestParam(required = false) String container) {
index 4bc4c76fc4c7edadf6f8e4994890a162044d76b7..09c4666d44757de4c338a70037e94c3c36aed6fa 100644 (file)
@@ -1,8 +1,8 @@
-/* 
- * 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, 
+/*
+ * 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
  *
  */
@@ -63,13 +63,13 @@ $(one.f.menu.right.bottom).each(function(index, value) {
 /**Troubleshoot modules*/
 one.f.troubleshooting = {
     rootUrl: "/controller/web/troubleshoot",
-    rightBottomDashlet: { 
+    rightBottomDashlet: {
         get: function() {
             var $rightBottomDashlet = $("#right-bottom").find(".dashlet");
             return $rightBottomDashlet;
         },
         setDashletHeader: function(label) {
-            $("#right-bottom li a")[0].innerHTML = label; 
+            $("#right-bottom li a")[0].innerHTML = label;
         }
     },
     createTable: function(columnNames, body) {
@@ -92,8 +92,11 @@ one.f.troubleshooting.existingNodes = {
             portsDataGrid: "one_f_troubleshooting_existingNodes_id_portsDataGrid",
             flowsDataGrid: "one_f_troubleshooting_existingNodes_id_flowsDataGrid",
             refreshFlowsButton:"one_f_troubleshooting_existingNodes_id_refreshFlowsButton",
-            refreshPortsButton:"one_f_troubleshooting_existingNodes_id_refreshPortsButton"
-
+            refreshPortsButton:"one_f_troubleshooting_existingNodes_id_refreshPortsButton",
+            modal : {
+                nodeInfo : "one_f_troubleshooting_existingNodes_id_modal_nodeInfo",
+                cancelButton : "one_f_troubleshooting_existingNodes_id_modal_cancelButton",
+            }
         },
         load: {
             main: function($dashlet) {
@@ -171,7 +174,7 @@ one.f.troubleshooting.existingNodes = {
                         $("#" + one.f.troubleshooting.existingNodes.id.portsDataGrid).datagrid({dataSource: dataSource});
                     });
                 } catch(e) {}
-            } 
+            }
         },
         ajax : function(url, callback) {
             $.getJSON(url, function(data) {
@@ -204,7 +207,9 @@ one.f.troubleshooting.existingNodes = {
                     data: data.nodeData,
                     formatter: function(items) {
                         $.each(items, function(index, item) {
-                            item["statistics"] = "<a href=\"javascript:one.f.troubleshooting.existingNodes.load.flows('" + item["nodeId"] + "');\">Flows</a>" + 
+                            item.nodeName = "<a href=\"javascript:one.f.troubleshooting.existingNodes.data.nodeInfo('"
+                                + item.nodeId + "');\">" + item.nodeName + "</a>"
+                            item["statistics"] = "<a href=\"javascript:one.f.troubleshooting.existingNodes.load.flows('" + item["nodeId"] + "');\">Flows</a>" +
                             " <a href=\"javascript:one.f.troubleshooting.existingNodes.load.ports('" + item["nodeId"] + "');\">Ports</a>";
                         });
                     },
@@ -461,6 +466,46 @@ one.f.troubleshooting.existingNodes = {
                     result.push(tr);
                 });
                 return result;
+            },
+            nodeInfo : function(nodeId){
+                $.getJSON(one.main.constants.address.prefix + "/troubleshoot/nodeInfo?nodeId=" + nodeId, function(content) {
+                    var h3 = 'Node Information'
+
+                    var headers = [ 'Description','Specification'];
+
+                    var attributes = ['table-striped', 'table-bordered', 'table-condensed'];
+                    var $table = one.lib.dashlet.table.table(attributes);
+                    var $thead = one.lib.dashlet.table.header(headers);
+                    $table.append($thead);
+
+                    var footer = [];
+
+                    var cancelButton = one.lib.dashlet.button.single("Cancel",
+                            one.f.troubleshooting.existingNodes.id.modal.nodeInfo, "", "");
+                    var $cancelButton = one.lib.dashlet.button.button(cancelButton);
+                    footer.push($cancelButton);
+
+                    var body = []
+                    $.each(content, function(key, value) {
+                        var tr = {};
+                        var entry = [];
+
+                        entry.push(key);
+                        entry.push(value);
+
+                        tr.entry = entry;
+                        body.push(tr);
+                    });
+                    var $tbody = one.lib.dashlet.table.body(body);
+                    $table.append($tbody);
+
+                    var $modal = one.lib.modal.spawn(one.f.troubleshooting.existingNodes.id.modal.nodeInfo, h3, $table , footer);
+                    $modal.modal();
+
+                    $('#'+one.f.troubleshooting.existingNodes.id.modal.nodeInfo, $modal).click(function() {
+                        $modal.modal('hide');
+                    });
+                });
             }
         }
 };
@@ -488,7 +533,7 @@ one.f.troubleshooting.uptime = {
                 $("#" + one.f.troubleshooting.uptime.id.datagrid).datagrid({dataSource: dataSource});
             });
     },
-    
+
     ajax : {
         main : function(url, requestData, callback) {
             $.getJSON(url, requestData, function(data) {
@@ -496,7 +541,7 @@ one.f.troubleshooting.uptime = {
             });
         }
     },
-    
+
     data: {
         uptimeDataGrid: function(data) {
             var source = new StaticDataSource({
@@ -548,7 +593,7 @@ one.f.troubleshooting.statistics = {
         var $p = $(document.createElement('p'));
         $p.text('Please select a Flow or Ports statistics');
         $p.addClass('text-center').addClass('text-info');
-        
+
         $dashlet.append($none)
             .append($p);
     }