summaryrefslogtreecommitdiffstats
path: root/infra
diff options
context:
space:
mode:
authorMaros Marsalek <mmarsale@cisco.com>2016-07-27 11:05:51 +0200
committerMaros Marsalek <mmarsale@cisco.com>2016-07-29 16:32:07 +0200
commit0578156b721fa01c8c645b8f9625ecebdb6449e4 (patch)
tree49d36f24e5d984a8c9f151b1440de88619f8b7de /infra
parent007d4542388ca89be409ce1a4a4c7a36ddcb538f (diff)
HONEYCOMB-130: Separate v3po plugin from HC infra
Creating folders: - common/ - infra/ - v3po/ - vpp-common/ Change-Id: I2c39e1b17e39e7c0f0628f44aa5fe08563fa06e4 Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
Diffstat (limited to 'infra')
-rw-r--r--infra/Readme.adoc67
-rw-r--r--infra/artifacts/pom.xml96
-rw-r--r--infra/cfg-init/pom.xml55
-rw-r--r--infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/AbstractDataTreeConverter.java114
-rw-r--r--infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/DataTreeInitializer.java51
-rw-r--r--infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/InitializerRegistry.java33
-rw-r--r--infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/InitializerRegistryImpl.java52
-rw-r--r--infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/RestoringInitializer.java112
-rw-r--r--infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/ConfigurationInitializerRegistryModule.java54
-rw-r--r--infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/ConfigurationInitializerRegistryModuleFactory.java13
-rw-r--r--infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/PersistedFileInitializerModule.java38
-rw-r--r--infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/PersistedFileInitializerModuleFactory.java13
-rw-r--r--infra/cfg-init/src/main/yang/vpp-cfg-init.yang117
-rw-r--r--infra/cfg-init/src/test/java/io/fd/honeycomb/v3po/vpp/data/init/InitializerRegistryImplTest.java66
-rw-r--r--infra/data-api/Readme.adoc10
-rw-r--r--infra/data-api/pom.xml55
-rw-r--r--infra/data-api/src/main/java/io/fd/honeycomb/v3po/data/DataModification.java70
-rw-r--r--infra/data-api/src/main/java/io/fd/honeycomb/v3po/data/ModifiableDataManager.java33
-rw-r--r--infra/data-api/src/main/java/io/fd/honeycomb/v3po/data/ReadableDataManager.java40
-rw-r--r--infra/data-api/src/main/yang/data-api.yang38
-rw-r--r--infra/data-impl/Readme.adoc43
-rw-r--r--infra/data-impl/pom.xml106
-rw-r--r--infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataBroker.java198
-rw-r--r--infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegator.java236
-rw-r--r--infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeManager.java122
-rw-r--r--infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModificationDiff.java278
-rw-r--r--infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapter.java151
-rw-r--r--infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransaction.java119
-rw-r--r--infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadWriteTransaction.java101
-rw-r--r--infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadableDataTreeDelegator.java242
-rw-r--r--infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/WriteTransaction.java177
-rw-r--r--infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/ConfigDataTreeModule.java71
-rw-r--r--infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/ConfigDataTreeModuleFactory.java13
-rw-r--r--infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/InMemoryDataTreeModule.java79
-rw-r--r--infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/InMemoryDataTreeModuleFactory.java13
-rw-r--r--infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/OperationalDataTreeModule.java65
-rw-r--r--infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/OperationalDataTreeModuleFactory.java13
-rw-r--r--infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/PersistingDataTreeAdapterModule.java38
-rw-r--r--infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/PersistingDataTreeAdapterModuleFactory.java13
-rw-r--r--infra/data-impl/src/main/yang/data-impl.yang179
-rw-r--r--infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/DataBrokerTest.java111
-rw-r--r--infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegatorTest.java269
-rw-r--r--infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ModificationDiffTest.java427
-rw-r--r--infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapterTest.java69
-rw-r--r--infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransactionTest.java68
-rw-r--r--infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadWriteTransactionTest.java111
-rw-r--r--infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadableDataTreeDelegatorTest.java192
-rw-r--r--infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/WriteTransactionTest.java128
-rw-r--r--infra/data-impl/src/test/resources/test-diff.yang54
-rw-r--r--infra/features/pom.xml217
-rw-r--r--infra/features/src/main/features/features.xml70
-rw-r--r--infra/impl/pom.xml130
-rw-r--r--infra/impl/src/main/config/context-datatree-config.xml144
-rw-r--r--infra/impl/src/main/config/default-config.xml253
-rw-r--r--infra/impl/src/main/config/initializer-config.xml188
-rw-r--r--infra/impl/src/main/config/netconf-north-config.xml496
-rw-r--r--infra/impl/src/main/config/restconf-north-config.xml37
-rw-r--r--infra/impl/src/main/java/io/fd/honeycomb/v3po/impl/NorthboundFacadeHoneycombDOMBroker.java206
-rw-r--r--infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/ContextDataBrokerModule.java26
-rw-r--r--infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/ContextDataBrokerModuleFactory.java13
-rw-r--r--infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/DataBrokerModule.java34
-rw-r--r--infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/DataBrokerModuleFactory.java13
-rw-r--r--infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfBindingBrokerModule.java117
-rw-r--r--infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfBindingBrokerModuleFactory.java13
-rw-r--r--infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfMonitoringReaderModule.java46
-rw-r--r--infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfMonitoringReaderModuleFactory.java13
-rw-r--r--infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModule.java60
-rw-r--r--infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactory.java28
-rw-r--r--infra/impl/src/main/yang/v3po-impl.yang155
-rw-r--r--infra/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactoryTest.java26
-rw-r--r--infra/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleTest.java70
-rw-r--r--infra/it/it-test/pom.xml66
-rw-r--r--infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/AbstractInfraTest.java106
-rw-r--r--infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombReadInfraTest.java460
-rw-r--r--infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombSubtreeReadInfraTest.java150
-rw-r--r--infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombWriteInfraTest.java521
-rw-r--r--infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/Ids.java62
-rw-r--r--infra/it/pom.xml51
-rw-r--r--infra/it/test-model/pom.xml36
-rw-r--r--infra/it/test-model/src/main/yang/hc-test.yang123
-rw-r--r--infra/karaf/pom.xml74
-rw-r--r--infra/notification/api/pom.xml40
-rw-r--r--infra/notification/api/src/main/java/io/fd/honeycomb/v3po/notification/ManagedNotificationProducer.java38
-rw-r--r--infra/notification/api/src/main/java/io/fd/honeycomb/v3po/notification/NotificationCollector.java35
-rw-r--r--infra/notification/api/src/main/java/io/fd/honeycomb/v3po/notification/NotificationProducer.java37
-rw-r--r--infra/notification/api/src/main/yang/notification-api.yang31
-rw-r--r--infra/notification/impl/pom.xml92
-rw-r--r--infra/notification/impl/src/main/config/default-config.xml71
-rw-r--r--infra/notification/impl/src/main/config/notification-to-netconf-config.xml58
-rw-r--r--infra/notification/impl/src/main/java/io/fd/honeycomb/v3po/notification/impl/HoneycombNotificationCollector.java66
-rw-r--r--infra/notification/impl/src/main/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerRegistry.java112
-rw-r--r--infra/notification/impl/src/main/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerTracker.java109
-rw-r--r--infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombDomNotificationServiceModule.java27
-rw-r--r--infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombDomNotificationServiceModuleFactory.java13
-rw-r--r--infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombNotificationManagerModule.java93
-rw-r--r--infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombNotificationManagerModuleFactory.java13
-rw-r--r--infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombNotificationToNetconfTranslatorModule.java157
-rw-r--r--infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombNotificationToNetconfTranslatorModuleFactory.java13
-rw-r--r--infra/notification/impl/src/main/yang/notification-impl.yang141
-rw-r--r--infra/notification/impl/src/test/java/io/fd/honeycomb/v3po/notification/impl/HoneycombNotificationCollectorTest.java63
-rw-r--r--infra/notification/impl/src/test/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerRegistryTest.java98
-rw-r--r--infra/notification/impl/src/test/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerTrackerTest.java67
-rw-r--r--infra/notification/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/NoetificationToNetconfModuleTest.java81
-rw-r--r--infra/notification/pom.xml56
-rw-r--r--infra/pom.xml68
-rw-r--r--infra/postman_rest_collection.json1386
-rw-r--r--infra/translate-api/Readme.adoc9
-rw-r--r--infra/translate-api/pom.xml67
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/MappingContext.java66
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModifiableSubtreeManagerRegistryBuilder.java77
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationCache.java49
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationContext.java44
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/SubtreeManager.java39
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/SubtreeManagerRegistryBuilder.java22
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/TranslationException.java38
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ListReader.java66
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadContext.java26
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadFailedException.java61
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/Reader.java76
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReaderFactory.java38
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ModifiableReaderRegistryBuilder.java41
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ReaderRegistry.java62
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/registry/ReaderRegistryBuilder.java27
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/DataObjectUpdate.java114
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/ListWriter.java33
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriteContext.java50
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriteFailedException.java166
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/Writer.java48
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriterFactory.java38
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/ModifiableWriterRegistryBuilder.java31
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/WriterRegistry.java213
-rw-r--r--infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/registry/WriterRegistryBuilder.java27
-rw-r--r--infra/translate-api/src/main/yang/translate-api.yang52
-rw-r--r--infra/translate-api/src/test/java/io/fd/honeycomb/v3po/translate/ReadFailedExceptionTest.java50
-rw-r--r--infra/translate-impl/Readme.adoc9
-rw-r--r--infra/translate-impl/pom.xml82
-rw-r--r--infra/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/GenericListReader.java117
-rw-r--r--infra/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/GenericReader.java70
-rw-r--r--infra/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/GenericListWriter.java106
-rw-r--r--infra/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/write/GenericWriter.java61
-rw-r--r--infra/translate-impl/src/test/java/io/fd/honeycomb/v3po/translate/impl/write/GenericListWriterTest.java83
-rw-r--r--infra/translate-impl/src/test/java/io/fd/honeycomb/v3po/translate/impl/write/GenericWriterTest.java64
-rw-r--r--infra/translate-spi/Readme.adoc4
-rw-r--r--infra/translate-spi/pom.xml72
-rw-r--r--infra/translate-spi/src/main/java/io/fd/honeycomb/v3po/translate/spi/read/ListReaderCustomizer.java63
-rw-r--r--infra/translate-spi/src/main/java/io/fd/honeycomb/v3po/translate/spi/read/ReaderCustomizer.java63
-rw-r--r--infra/translate-spi/src/main/java/io/fd/honeycomb/v3po/translate/spi/write/ListWriterCustomizer.java34
-rw-r--r--infra/translate-spi/src/main/java/io/fd/honeycomb/v3po/translate/spi/write/WriterCustomizer.java75
-rw-r--r--infra/translate-utils/Readme.adoc3
-rw-r--r--infra/translate-utils/pom.xml93
-rw-r--r--infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/AbstractSubtreeManagerRegistryBuilderBuilder.java213
-rw-r--r--infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/JsonUtils.java102
-rw-r--r--infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/RWUtils.java186
-rw-r--r--infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/ReflectionUtils.java79
-rw-r--r--infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/TransactionMappingContext.java75
-rw-r--r--infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/AbstractGenericReader.java90
-rw-r--r--infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/BindingBrokerReader.java96
-rw-r--r--infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/KeepaliveReaderWrapper.java173
-rw-r--r--infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/NoopReaderCustomizer.java34
-rw-r--r--infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/ReflexiveListReaderCustomizer.java65
-rw-r--r--infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/ReflexiveReader.java57
-rw-r--r--infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/ReflexiveReaderCustomizer.java103
-rw-r--r--infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/registry/CompositeReader.java202
-rw-r--r--infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/registry/CompositeReaderRegistry.java117
-rw-r--r--infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/registry/CompositeReaderRegistryBuilder.java109
-rw-r--r--infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/registry/SubtreeReader.java250
-rw-r--r--infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/registry/TypeHierarchy.java101
-rw-r--r--infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/AbstractGenericWriter.java137
-rw-r--r--infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/NoopWriterRegistry.java40
-rw-r--r--infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/TransactionWriteContext.java121
-rw-r--r--infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/registry/FlatWriterRegistry.java315
-rw-r--r--infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/registry/FlatWriterRegistryBuilder.java71
-rw-r--r--infra/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/write/registry/SubtreeWriter.java85
-rw-r--r--infra/translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/translate/utils/rev160406/DelegatingReaderRegistryModule.java25
-rw-r--r--infra/translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/translate/utils/rev160406/DelegatingReaderRegistryModuleFactory.java20
-rw-r--r--infra/translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/translate/utils/rev160406/DelegatingWriterRegistryModule.java26
-rw-r--r--infra/translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/translate/utils/rev160406/DelegatingWriterRegistryModuleFactory.java13
-rw-r--r--infra/translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/translate/utils/rev160406/NoopWriterRegistryModule.java38
-rw-r--r--infra/translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/translate/utils/rev160406/NoopWriterRegistryModuleFactory.java13
-rw-r--r--infra/translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/translate/utils/rev160406/RealtimeMappingContextModule.java84
-rw-r--r--infra/translate-utils/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/translate/utils/rev160406/RealtimeMappingContextModuleFactory.java13
-rw-r--r--infra/translate-utils/src/main/yang/translate-utils.yang95
-rw-r--r--infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/impl/write/util/TransactionWriteContextTest.java131
-rw-r--r--infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/DataObjects.java52
-rw-r--r--infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/JsonUtilsTest.java109
-rw-r--r--infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/read/registry/CompositeReaderRegistryBuilderTest.java114
-rw-r--r--infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/read/registry/SubtreeReaderTest.java124
-rw-r--r--infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/read/registry/TypeHierarchyTest.java69
-rw-r--r--infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/write/registry/FlatWriterRegistryBuilderTest.java131
-rw-r--r--infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/write/registry/FlatWriterRegistryTest.java264
-rw-r--r--infra/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/write/registry/SubtreeWriterTest.java84
-rw-r--r--infra/translate-utils/src/test/resources/expected-persisted-output.txt8
-rw-r--r--infra/translate-utils/src/test/resources/test-persistence.yang22
193 files changed, 18667 insertions, 0 deletions
diff --git a/infra/Readme.adoc b/infra/Readme.adoc
new file mode 100644
index 0000000..33e882f
--- /dev/null
+++ b/infra/Readme.adoc
@@ -0,0 +1,67 @@
+= Honeycomb
+
+Honeycomb is an VPP agent that runs the same host as a VPP instance
+and exposes YANG models via NETCONF and RESTCONF to allow management of that VPP instance.
+Honeycomb uses jAPI to communicate with the VPP.
+
+[ditaa, "hc-architecture"]
+....
+ /------------------\
+ ODL | RESTCONF/NETCONF |
+ \-+--------------+-/
+ | ^
+---------------------|--------------|---------------------
+ v |
+ /------------------\
+ | Data layer |
+ \-+--------------+-/
+ | ^
+ Honeycomb v |
+ /-----+--------------+-----\
+ | Translation layer |
+ \----+----------------+----+
+ | VPP SPI impl |
+ +---+------+-----+
+ | ^
+------------------------|------|--------------------------
+ v |
+ ++------++
+ | jAPI |
+ VPP /----+--------+------\
+ | VPP |
+ \--------------------/
+
+....
+
+== NETCONF/RESTCONF layer
+
+NETCONF and RESTCONF support is provided by ODL (Honeycomb is an ODL application).
+In the future we plan to minimize ODL dependencies or completely remove karaf.
+
+Transaction functionality is provided by the data layer.
+
+== Data layer
+
+Models CONFIG data store as a DataTree.
+
+OPERATIONAL data store reads are passed directly to the translation layer.
+
+Provides transaction functionality for NETCONF/RESTCONF layer.
+
+
+== Translation layer
+
+Extensible API for translation between Binding Aware data and actual device data.
+Consists of readers and writers responsible for communication with the device.
+
+Provides registry of readers and writers for the data layer.
+
+== Supported features
+
+List of supported requests for RESTCONF northbound interface can be found in
+postman_rest_collection.json within the codebase.
+It is a POSTMAN compatible collection and can be imported into POSTMAN application.
+
+
+
+
diff --git a/infra/artifacts/pom.xml b/infra/artifacts/pom.xml
new file mode 100644
index 0000000..c2bbe16
--- /dev/null
+++ b/infra/artifacts/pom.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<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>
+ <groupId>io.fd.honeycomb</groupId>
+ <artifactId>honeycomb-artifacts</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <packaging>pom</packaging>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>data-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>notification-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>notification-impl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>notification-spi</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>data-utils</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>data-impl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>translate-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>translate-spi</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>translate-impl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>translate-utils</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>cfg-init</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>honeycomb-impl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>honeycomb-features</artifactId>
+ <version>${project.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+</project>
diff --git a/infra/cfg-init/pom.xml b/infra/cfg-init/pom.xml
new file mode 100644
index 0000000..ddacb63
--- /dev/null
+++ b/infra/cfg-init/pom.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<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">
+ <parent>
+ <groupId>io.fd.honeycomb.common</groupId>
+ <artifactId>impl-parent</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <relativePath>../../common/impl-parent</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>io.fd.honeycomb</groupId>
+ <artifactId>cfg-init</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>translate-impl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>data-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <!-- Testing Dependencies -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git a/infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/AbstractDataTreeConverter.java b/infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/AbstractDataTreeConverter.java
new file mode 100644
index 0000000..f005826
--- /dev/null
+++ b/infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/AbstractDataTreeConverter.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.vpp.data.init;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Base class for initializers which perform conversion between operational and config YANG model.
+ *
+ * @param <C> Config data object
+ * @param <O> Operational data object
+ */
+@Beta
+public abstract class AbstractDataTreeConverter<O extends DataObject, C extends DataObject>
+ implements DataTreeInitializer {
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractDataTreeConverter.class);
+
+ private final InstanceIdentifier<O> idOper;
+ private final InstanceIdentifier<C> idConfig;
+ private final DataBroker bindingDataBroker;
+
+ public AbstractDataTreeConverter(final DataBroker bindingDataBroker,
+ final InstanceIdentifier<O> operRootId,
+ final InstanceIdentifier<C> cfgRootId) {
+ this.bindingDataBroker = checkNotNull(bindingDataBroker, "bindingDataBroker should not be null");
+ this.idOper = checkNotNull(operRootId, "operRootId should not be null");
+ this.idConfig = checkNotNull(cfgRootId, "cfgRootId should not be null");
+ }
+
+ @Override
+ public void close() throws Exception {
+ LOG.debug("AbstractDataTreeConverter.close()");
+ // Not removing initialized data, since this works in cooperation with persistence, it could remove
+ // data restored by persistence or remove user configured data when shutting down HC
+ }
+
+ @Override
+ public final void initialize() throws InitializeException {
+ LOG.debug("AbstractDataTreeConverter.initialize() from(oper): {}, to(cfg): {}", idOper, idConfig);
+ final Optional<O> data = readData();
+
+ if (data.isPresent()) {
+ LOG.debug("Config initialization, operational data={}", data);
+
+ final O operationalData = data.get();
+ final C configData = convert(operationalData);
+
+ try {
+ LOG.debug("Initializing config with data={}", configData);
+ writeData(configData);
+ LOG.info("Config initialization successful from(oper): {}, to(cfg): {}", idOper, idConfig);
+ } catch (TransactionCommitFailedException e) {
+ throw new InitializeException("Failed to perform config initialization", e);
+ }
+ } else {
+ LOG.info("Data is not present under: {}, no initial changes to config at: {}", idOper, idConfig);
+ }
+ }
+
+ private Optional<O> readData() {
+ try (ReadOnlyTransaction readTx = bindingDataBroker.newReadOnlyTransaction()) {
+ final CheckedFuture<Optional<O>, org.opendaylight.controller.md.sal.common.api.data.ReadFailedException>
+ readFuture = readTx.read(LogicalDatastoreType.OPERATIONAL, idOper);
+ return readFuture.checkedGet();
+ } catch (org.opendaylight.controller.md.sal.common.api.data.ReadFailedException e) {
+ LOG.warn("Failed to read operational state", e);
+ }
+ return Optional.absent();
+ }
+
+ private void writeData(final C configData) throws TransactionCommitFailedException {
+ final WriteTransaction writeTx = bindingDataBroker.newWriteOnlyTransaction();
+ // Merge(instead of put) has to be used due to dynamic start, this might be executed multiple times
+ // and might overwrite config restored from persisted file with the same incomplete config.
+ // Making the entire configuration trigger VPP twice (on second persis ... and VPP does not like that
+ writeTx.merge(LogicalDatastoreType.CONFIGURATION, idConfig, configData);
+ writeTx.submit().checkedGet();
+ }
+
+ // TODO make this class concrete and use function dependency instead of abstract method
+ /**
+ * Converts operational data to config data for given root node
+ * @param operationalData data object representing operational data
+ * @return data object representing config data
+ */
+ protected abstract C convert(final O operationalData);
+}
diff --git a/infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/DataTreeInitializer.java b/infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/DataTreeInitializer.java
new file mode 100644
index 0000000..d760401
--- /dev/null
+++ b/infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/DataTreeInitializer.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.vpp.data.init;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * Service for config data tree initialization.
+ * Implementation reads operational data and initializes config data tree.
+ * Initialization does not cause any change in VPP state, unlike ordinary writes to config.
+ */
+@Beta
+public interface DataTreeInitializer extends AutoCloseable {
+
+ /**
+ * Initializes config data tree for supported root node.
+ * @throws InitializeException if initialization failed
+ */
+ void initialize() throws InitializeException;
+
+ /**
+ * Removes all data managed by the initializer.
+ */
+ @Override
+ void close() throws Exception;
+
+ class InitializeException extends Exception {
+
+ public InitializeException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+
+ public InitializeException(final String msg) {
+ super(msg);
+ }
+ }
+}
diff --git a/infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/InitializerRegistry.java b/infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/InitializerRegistry.java
new file mode 100644
index 0000000..8760f0f
--- /dev/null
+++ b/infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/InitializerRegistry.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.vpp.data.init;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * Data tree initializer suitable as a holder for all other root initializers, providing initializeAll feature.
+ */
+@Beta
+public interface InitializerRegistry extends DataTreeInitializer {
+
+ /**
+ * Performs initialize on all registered root initializers.
+ * @throws if initialization failed
+ */
+ @Override
+ void initialize() throws InitializeException;
+}
diff --git a/infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/InitializerRegistryImpl.java b/infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/InitializerRegistryImpl.java
new file mode 100644
index 0000000..e5220f7
--- /dev/null
+++ b/infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/InitializerRegistryImpl.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.vpp.data.init;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.List;
+import javax.annotation.Nonnull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class InitializerRegistryImpl implements InitializerRegistry {
+ private static final Logger LOG = LoggerFactory.getLogger(InitializerRegistryImpl.class);
+ private final List<DataTreeInitializer> initializers;
+
+ public InitializerRegistryImpl(@Nonnull List<DataTreeInitializer> initializers) {
+ this.initializers = checkNotNull(initializers, "initializers should not be null");
+ checkArgument(!initializers.contains(null), "initializers should not contain null elements");
+ }
+
+ @Override
+ public void close() throws Exception {
+ LOG.debug("InitializerRegistryImpl.close()");
+ for (DataTreeInitializer initializer : initializers) {
+ initializer.close();
+ }
+ }
+
+ @Override
+ public void initialize() throws InitializeException {
+ // TODO check if readers are there
+ LOG.debug("InitializerRegistryImpl.initialize()");
+ for (DataTreeInitializer initializer : initializers) {
+ initializer.initialize();
+ }
+ }
+}
diff --git a/infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/RestoringInitializer.java b/infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/RestoringInitializer.java
new file mode 100644
index 0000000..abc3f54
--- /dev/null
+++ b/infra/cfg-init/src/main/java/io/fd/honeycomb/v3po/vpp/data/init/RestoringInitializer.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.vpp.data.init;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import io.fd.honeycomb.v3po.translate.util.JsonUtils;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.controller.sal.core.api.model.SchemaService;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407.RestorationType;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RestoringInitializer implements DataTreeInitializer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(RestoringInitializer.class);
+
+ private final SchemaService schemaService;
+ private final Path path;
+ private final DOMDataBroker dataTree;
+ private final RestorationType restorationType;
+ private final LogicalDatastoreType datastoreType;
+
+ public RestoringInitializer(@Nonnull final SchemaService schemaService,
+ @Nonnull final Path path,
+ @Nonnull final DOMDataBroker dataTree,
+ @Nonnull final RestorationType restorationType,
+ @Nonnull final LogicalDatastoreType datastoreType) {
+ this.schemaService = schemaService;
+ this.datastoreType = datastoreType;
+ this.path = checkStorage(path);
+ this.dataTree = dataTree;
+ this.restorationType = restorationType;
+ }
+
+ private Path checkStorage(final Path path) {
+ if (Files.exists(path)) {
+ checkArgument(!Files.isDirectory(path), "File %s is a directory", path);
+ checkArgument(Files.isReadable(path), "File %s is not readable", path);
+ }
+
+ return path;
+ }
+
+ @Override
+ public void initialize() throws InitializeException {
+ LOG.debug("Starting restoration of {} from {} using {}", dataTree, path, restorationType);
+ if(!Files.exists(path)) {
+ LOG.debug("Persist file {} does not exist. Skipping restoration", path);
+ return;
+ }
+
+ try {
+ final ContainerNode containerNode = JsonUtils
+ .readJsonRoot(schemaService.getGlobalContext(), Files.newInputStream(path, StandardOpenOption.READ));
+
+ final DOMDataWriteTransaction domDataWriteTransaction = dataTree.newWriteOnlyTransaction();
+ for (DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> dataContainerChild : containerNode
+ .getValue()) {
+ final YangInstanceIdentifier iid = YangInstanceIdentifier.create(dataContainerChild.getIdentifier());
+ LOG.trace("Restoring {} from {}", iid, path);
+
+ switch (restorationType) {
+ case Merge:
+ domDataWriteTransaction.merge(datastoreType, iid, dataContainerChild);
+ break;
+ case Put:
+ domDataWriteTransaction.put(datastoreType, iid, dataContainerChild);
+ break;
+ default:
+ throw new InitializeException(
+ "Unable to initialize data using " + restorationType + " restoration strategy. Unsupported");
+ }
+ }
+
+ // Block here to prevent subsequent initializers processing before context is fully restored
+ domDataWriteTransaction.submit().checkedGet();
+ LOG.debug("Data from {} restored successfully", path);
+
+ } catch (IOException | TransactionCommitFailedException e) {
+ throw new InitializeException("Unable to restore data from " + path, e);
+ }
+ }
+
+ @Override
+ public void close() {}
+}
diff --git a/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/ConfigurationInitializerRegistryModule.java b/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/ConfigurationInitializerRegistryModule.java
new file mode 100644
index 0000000..3fff82e
--- /dev/null
+++ b/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/ConfigurationInitializerRegistryModule.java
@@ -0,0 +1,54 @@
+package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407;
+
+import io.fd.honeycomb.v3po.vpp.data.init.InitializerRegistry;
+import io.fd.honeycomb.v3po.vpp.data.init.InitializerRegistryImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+* Initializer registry, delegating initialization to a list of initializers
+*/
+public class ConfigurationInitializerRegistryModule extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407.AbstractConfigurationInitializerRegistryModule {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ConfigurationInitializerRegistryModule.class);
+
+ public ConfigurationInitializerRegistryModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public ConfigurationInitializerRegistryModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407.ConfigurationInitializerRegistryModule oldModule, java.lang.AutoCloseable oldInstance) {
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ public void customValidation() {
+ // add custom validation form module attributes here.
+ }
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+ LOG.info("VppConfigurationInitializerModule.createInstance(): initialization started");
+
+ final InitializerRegistry initializer = new InitializerRegistryImpl(getInitializersDependency());
+
+ try {
+ // Initialize contexts first so that other initializers can find any relevant mapping before initializing
+ // configuration to what is already in VPP
+ getPersistedContextInitializerDependency().initialize();
+ LOG.info("Persisted context restored successfully");
+ // Initialize all registered initializers
+ initializer.initialize();
+ LOG.info("VPP configuration initialized successfully from VPP");
+ // Initialize stored configuration on top
+ getPersistedConfigInitializerDependency().initialize();
+ LOG.info("Persisted configuration restored successfully");
+ } catch (Exception e) {
+ LOG.warn("Failed to initialize config", e);
+ }
+
+ LOG.info("Honeycomb initialized");
+
+ return initializer;
+ }
+
+}
diff --git a/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/ConfigurationInitializerRegistryModuleFactory.java b/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/ConfigurationInitializerRegistryModuleFactory.java
new file mode 100644
index 0000000..f07be95
--- /dev/null
+++ b/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/ConfigurationInitializerRegistryModuleFactory.java
@@ -0,0 +1,13 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: vpp-cfg-init yang module local name: cfg-initializer-registry
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Wed May 18 14:43:49 CEST 2016
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407;
+public class ConfigurationInitializerRegistryModuleFactory extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407.AbstractConfigurationInitializerRegistryModuleFactory {
+
+}
diff --git a/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/PersistedFileInitializerModule.java b/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/PersistedFileInitializerModule.java
new file mode 100644
index 0000000..188d164
--- /dev/null
+++ b/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/PersistedFileInitializerModule.java
@@ -0,0 +1,38 @@
+package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407;
+
+import io.fd.honeycomb.v3po.vpp.data.init.RestoringInitializer;
+import java.nio.file.InvalidPathException;
+import java.nio.file.Paths;
+import org.opendaylight.controller.config.api.JmxAttributeValidationException;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.api.rev160411.DatatreeType;
+
+/**
+* Initializer restoring data from a persisted file
+*/
+public class PersistedFileInitializerModule extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407.AbstractPersistedFileInitializerModule {
+ public PersistedFileInitializerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public PersistedFileInitializerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407.PersistedFileInitializerModule oldModule, java.lang.AutoCloseable oldInstance) {
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ public void customValidation() {
+ try {
+ Paths.get(getPersistFilePath());
+ } catch (InvalidPathException e) {
+ throw new JmxAttributeValidationException("Invalid persist path", e, persistFilePathJmxAttribute);
+ }
+ }
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+ return new RestoringInitializer(getSchemaServiceDependency(), Paths.get(getPersistFilePath()),
+ getDomDataBrokerDependency(), getRestorationType(),
+ getDatastoreType() == DatatreeType.Config ? LogicalDatastoreType.CONFIGURATION : LogicalDatastoreType.OPERATIONAL);
+ }
+
+}
diff --git a/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/PersistedFileInitializerModuleFactory.java b/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/PersistedFileInitializerModuleFactory.java
new file mode 100644
index 0000000..1d7a3c9
--- /dev/null
+++ b/infra/cfg-init/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/vpp/data/init/rev160407/PersistedFileInitializerModuleFactory.java
@@ -0,0 +1,13 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: vpp-cfg-init yang module local name: persisted-file-initializer
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Wed May 18 13:48:52 CEST 2016
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407;
+public class PersistedFileInitializerModuleFactory extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.vpp.data.init.rev160407.AbstractPersistedFileInitializerModuleFactory {
+
+}
diff --git a/infra/cfg-init/src/main/yang/vpp-cfg-init.yang b/infra/cfg-init/src/main/yang/vpp-cfg-init.yang
new file mode 100644
index 0000000..52750d9
--- /dev/null
+++ b/infra/cfg-init/src/main/yang/vpp-cfg-init.yang
@@ -0,0 +1,117 @@
+module vpp-cfg-init {
+ yang-version 1;
+ namespace "urn:honeycomb:params:xml:ns:yang:vpp:data:init";
+ prefix "init";
+
+ import config { prefix config; revision-date 2013-04-05; }
+ import opendaylight-md-sal-dom {prefix dom;}
+ import translate-api { prefix tapi; revision-date 2016-04-06; }
+ import data-api { prefix dapi; revision-date 2016-04-11; }
+
+ description
+ "This module contains initializers for VPP config data tree";
+
+ revision "2016-04-07" {
+ description
+ "Initial revision";
+ }
+
+ identity cfg-initializer {
+ base "config:service-type";
+ config:java-class io.fd.honeycomb.v3po.vpp.data.init.DataTreeInitializer;
+ }
+
+ identity cfg-initializer-registry {
+ base config:module-type;
+ config:provided-service cfg-initializer;
+ config:java-name-prefix ConfigurationInitializerRegistry;
+ description "Initializer registry, delegating initialization to a list of initializers";
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case cfg-initializer-registry {
+ when "/config:modules/config:module/config:type = 'cfg-initializer-registry'";
+
+ list initializers {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity cfg-initializer;
+ }
+ }
+ }
+
+ container persisted-context-initializer {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity cfg-initializer;
+ }
+ }
+ }
+
+ container persisted-config-initializer {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity cfg-initializer;
+ }
+ }
+ }
+ }
+ }
+
+ identity persisted-file-initializer {
+ base config:module-type;
+ config:provided-service cfg-initializer;
+ description "Initializer restoring data from a persisted file";
+ }
+
+ typedef restoration-type {
+ type enumeration {
+ enum merge;
+ enum put;
+ }
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case persisted-file-initializer {
+ when "/config:modules/config:module/config:type = 'persisted-file-initializer'";
+
+ container dom-data-broker {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity dom:dom-async-data-broker;
+ }
+ }
+ }
+
+ container schema-service {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity dom:schema-service;
+ }
+ }
+ }
+
+ leaf persist-file-path {
+ type string;
+ mandatory true;
+ }
+
+ leaf restoration-type {
+ type restoration-type;
+ default merge;
+ }
+
+
+ leaf datastore-type {
+ type dapi:datatree-type;
+ mandatory true;
+ }
+ }
+ }
+
+} \ No newline at end of file
diff --git a/infra/cfg-init/src/test/java/io/fd/honeycomb/v3po/vpp/data/init/InitializerRegistryImplTest.java b/infra/cfg-init/src/test/java/io/fd/honeycomb/v3po/vpp/data/init/InitializerRegistryImplTest.java
new file mode 100644
index 0000000..d562fb6
--- /dev/null
+++ b/infra/cfg-init/src/test/java/io/fd/honeycomb/v3po/vpp/data/init/InitializerRegistryImplTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.vpp.data.init;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import java.util.Arrays;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+
+public class InitializerRegistryImplTest {
+
+ @Mock(name="dti1")
+ private DataTreeInitializer dti1;
+ @Mock(name="dti2")
+ private DataTreeInitializer dti2;
+ @Mock(name="dti3")
+ private DataTreeInitializer dti3;
+
+ private InitializerRegistryImpl initializerRegistry;
+
+ @Before
+ public void setUp() throws Exception {
+ initMocks(this);
+ initializerRegistry = new InitializerRegistryImpl(Arrays.asList(dti1, dti2, dti3));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testConstructorFailed() throws Exception {
+ new InitializerRegistryImpl(Arrays.asList(dti1, null));
+ }
+
+ @Test
+ public void testInitialize() throws Exception {
+ initializerRegistry.initialize();
+
+ verify(dti1).initialize();
+ verify(dti2).initialize();
+ verify(dti3).initialize();
+ }
+
+ @Test
+ public void testClose() throws Exception {
+ initializerRegistry.close();
+
+ verify(dti1).close();
+ verify(dti2).close();
+ verify(dti3).close();
+ }
+} \ No newline at end of file
diff --git a/infra/data-api/Readme.adoc b/infra/data-api/Readme.adoc
new file mode 100644
index 0000000..a13c509
--- /dev/null
+++ b/infra/data-api/Readme.adoc
@@ -0,0 +1,10 @@
+= Honeycomb Data layer. API
+
+Provides data tree abstraction for data store modeling.
+ModifiableDataTree can be used to model CONFIG data store.
+ReadableDataTree can be used to model OPERATIONAL data store.
+
+
+
+
+
diff --git a/infra/data-api/pom.xml b/infra/data-api/pom.xml
new file mode 100644
index 0000000..eba388c
--- /dev/null
+++ b/infra/data-api/pom.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2016 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<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">
+ <parent>
+ <groupId>io.fd.honeycomb.common</groupId>
+ <artifactId>impl-parent</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <relativePath>../../common/impl-parent</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>io.fd.honeycomb</groupId>
+ <artifactId>data-api</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>translate-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-common-api</artifactId>
+ <!-- FIXME use dependency management -->
+ <version>1.3.2-Beryllium-SR2</version>
+ </dependency>
+
+ </dependencies>
+
+</project> \ No newline at end of file
diff --git a/infra/data-api/src/main/java/io/fd/honeycomb/v3po/data/DataModification.java b/infra/data-api/src/main/java/io/fd/honeycomb/v3po/data/DataModification.java
new file mode 100644
index 0000000..d05c557
--- /dev/null
+++ b/infra/data-api/src/main/java/io/fd/honeycomb/v3po/data/DataModification.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.data;
+
+import com.google.common.annotations.Beta;
+import io.fd.honeycomb.v3po.translate.TranslationException;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
+
+/**
+ * Modification of a {@link ModifiableDataManager}.
+ */
+@Beta
+public interface DataModification extends ReadableDataManager {
+
+ /**
+ * Delete the node at specified path.
+ *
+ * @param path Node path
+ */
+ void delete(YangInstanceIdentifier path);
+
+ /**
+ * Merge the specified data with the currently-present data
+ * at specified path.
+ *
+ * @param path Node path
+ * @param data Data to be merged
+ */
+ void merge(YangInstanceIdentifier path, NormalizedNode<?, ?> data);
+
+ /**
+ * Replace the data at specified path with supplied data.
+ *
+ * @param path Node path
+ * @param data New node data
+ */
+ void write(YangInstanceIdentifier path, NormalizedNode<?, ?> data);
+
+ /**
+ * Alters data tree using this modification.
+ *
+ * @throws DataValidationFailedException if modification data is not valid
+ * @throws TranslationException if failed while updating data tree state
+ */
+ void commit() throws DataValidationFailedException, TranslationException;
+
+ /**
+ * Validate and prepare modification before commit. Besides commit, no further operation is expected after validate
+ * and the behaviour is undefined.
+ *
+ * @throws DataValidationFailedException if modification data is not valid
+ */
+ void validate() throws DataValidationFailedException;
+}
diff --git a/infra/data-api/src/main/java/io/fd/honeycomb/v3po/data/ModifiableDataManager.java b/infra/data-api/src/main/java/io/fd/honeycomb/v3po/data/ModifiableDataManager.java
new file mode 100644
index 0000000..11cd513
--- /dev/null
+++ b/infra/data-api/src/main/java/io/fd/honeycomb/v3po/data/ModifiableDataManager.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.data;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * Facade over data tree that allows tree modification.
+ */
+@Beta
+public interface ModifiableDataManager extends ReadableDataManager {
+
+ /**
+ * Creates read-only snapshot of a ModifiableDataTree.
+ *
+ * @return modification
+ */
+ DataModification newModification();
+}
diff --git a/infra/data-api/src/main/java/io/fd/honeycomb/v3po/data/ReadableDataManager.java b/infra/data-api/src/main/java/io/fd/honeycomb/v3po/data/ReadableDataManager.java
new file mode 100644
index 0000000..0e98c09
--- /dev/null
+++ b/infra/data-api/src/main/java/io/fd/honeycomb/v3po/data/ReadableDataManager.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.data;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+/**
+ * Facade over data tree that allows reading tree nodes.
+ */
+@Beta
+public interface ReadableDataManager {
+
+ /**
+ * Reads a particular node from the data tree.
+ *
+ * @param path Path of the node
+ * @return a CheckFuture containing the result of the read.
+ */
+ CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(@Nonnull final YangInstanceIdentifier path);
+}
diff --git a/infra/data-api/src/main/yang/data-api.yang b/infra/data-api/src/main/yang/data-api.yang
new file mode 100644
index 0000000..693a73a
--- /dev/null
+++ b/infra/data-api/src/main/yang/data-api.yang
@@ -0,0 +1,38 @@
+module data-api {
+ yang-version 1;
+ namespace "urn:honeycomb:params:xml:ns:yang:data:api";
+ prefix "dapi";
+
+ import config { prefix config; revision-date 2013-04-05; }
+
+ description
+ "This module contains the base YANG data tree definitions
+ for data store modeling";
+
+ revision "2016-04-11" {
+ description
+ "Initial revision.";
+ }
+
+ identity data-tree {
+ base "config:service-type";
+ config:java-class org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
+ }
+
+ identity honeycomb-readable-data-tree {
+ base "config:service-type";
+ config:java-class io.fd.honeycomb.v3po.data.ReadableDataManager;
+ }
+
+ identity honeycomb-modifiable-data-tree {
+ base "config:service-type";
+ config:java-class io.fd.honeycomb.v3po.data.ModifiableDataManager;
+ }
+
+ typedef datatree-type {
+ type enumeration {
+ enum config;
+ enum oper;
+ }
+ }
+} \ No newline at end of file
diff --git a/infra/data-impl/Readme.adoc b/infra/data-impl/Readme.adoc
new file mode 100644
index 0000000..61b2653
--- /dev/null
+++ b/infra/data-impl/Readme.adoc
@@ -0,0 +1,43 @@
+= Honeycomb Data layer. Implementation
+
+Models CONFIG data store as a DataTree.
+
+Every read transaction reads directly from the DataTree.
+Every write transaction is validated, then passed to the translation layer.
+After successful update, config data tree is updated.
+
+OPERATIONAL data store reads are passed directly to the translation layer.
+
+Data transaction functionality for higher layers (i.e NETCONF/RESTCONF layer) is provided by DataBroker.
+
+[ditaa, "data-layer-architecture"]
+....
+ /------------------\
+ | RESTCONF/NETCONF |
+ \--------+---------/
+ |
+----------------------------|------------------------------------
+ v
+ /------------------\
+ | DataBroker |
+ \-+--------------+-/
+ | |
+ | read | read/write
+ Honeycomb v v
+ data layer /------+------\ /--+--------\ /----------\
+ | | | | | |
+ | Operational | | Config +------>+ DataTree +
+ | DataTree | | DataTree | | |
+ | | | | \----------/
+ \------+------/ \--+--------/
+ | |
+---------------------|--------------|----------------------------
+ v v
+ /-----+--------------+-----\
+ | Translation layer |
+ \--------------------------/
+....
+
+
+
+
diff --git a/infra/data-impl/pom.xml b/infra/data-impl/pom.xml
new file mode 100644
index 0000000..b80c796
--- /dev/null
+++ b/infra/data-impl/pom.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2016 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<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">
+ <parent>
+ <artifactId>impl-parent</artifactId>
+ <groupId>io.fd.honeycomb.common</groupId>
+ <version>1.0.0-SNAPSHOT</version>
+ <relativePath>../../common/impl-parent</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>io.fd.honeycomb</groupId>
+ <artifactId>data-impl</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>data-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>translate-utils</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-binding-dom-codec</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-core-api</artifactId>
+ <!-- FIXME use dependency management -->
+ <version>1.3.2-Beryllium-SR2</version>
+ </dependency>
+
+ <!-- FIXME workaround for https://git.opendaylight.org/gerrit/#/c/37499/-->
+ <dependency>
+ <groupId>org.opendaylight.netconf</groupId>
+ <artifactId>ietf-netconf-monitoring</artifactId>
+ <version>1.0.2-Beryllium-SR2</version>
+ </dependency>
+ <!-- FIXME workaround for https://git.opendaylight.org/gerrit/#/c/37499/-->
+ <dependency>
+ <groupId>org.opendaylight.netconf</groupId>
+ <artifactId>ietf-netconf-monitoring-extension</artifactId>
+ <version>1.0.2-Beryllium-SR2</version>
+ </dependency>
+
+ <!-- Testing Dependencies -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-jar-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+ <Export-Package>
+ io.fd.honeycomb.v3po.data.impl.*
+ </Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project> \ No newline at end of file
diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataBroker.java b/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataBroker.java
new file mode 100644
index 0000000..c418ed3
--- /dev/null
+++ b/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataBroker.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.data.impl;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.honeycomb.v3po.data.DataModification;
+import io.fd.honeycomb.v3po.data.ModifiableDataManager;
+import io.fd.honeycomb.v3po.data.ReadableDataManager;
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Map;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Data Broker which provides data transaction functionality for YANG capable data provider using {@link NormalizedNode}
+ * data format.
+ */
+public class DataBroker implements DOMDataBroker, Closeable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(DataBroker.class);
+ private final TransactionFactory transactionFactory;
+
+ /**
+ * Creates DataBroker instance.
+ *
+ * @param transactionFactory transaction producing factory
+ */
+ public DataBroker(final TransactionFactory transactionFactory) {
+ this.transactionFactory = transactionFactory;
+ }
+
+ @Override
+ public DOMDataReadOnlyTransaction newReadOnlyTransaction() {
+ LOG.trace("DataBroker({}).newReadOnlyTransaction()", this);
+ return transactionFactory.newReadOnlyTransaction();
+ }
+
+ @Override
+ public DOMDataReadWriteTransaction newReadWriteTransaction() {
+ LOG.trace("DataBroker({}).newReadWriteTransaction()", this);
+ return transactionFactory.newReadWriteTransaction();
+ }
+
+ @Override
+ public DOMDataWriteTransaction newWriteOnlyTransaction() {
+ LOG.trace("DataBroker({}).newWriteOnlyTransaction()", this);
+ return transactionFactory.newWriteOnlyTransaction();
+ }
+
+ @Override
+ public ListenerRegistration<DOMDataChangeListener> registerDataChangeListener(final LogicalDatastoreType store,
+ final YangInstanceIdentifier path,
+ final DOMDataChangeListener listener,
+ final DataChangeScope triggeringScope) {
+ throw new UnsupportedOperationException("Not supported");
+ }
+
+ @Override
+ public DOMTransactionChain createTransactionChain(final TransactionChainListener listener) {
+ throw new UnsupportedOperationException("Not supported");
+ }
+
+ @Nonnull
+ @Override
+ public Map<Class<? extends DOMDataBrokerExtension>, DOMDataBrokerExtension> getSupportedExtensions() {
+ return Collections.emptyMap();
+ }
+
+ /**
+ * Create DataBroker for a modifiable config DT, but only readable Operational
+ */
+ @Nonnull
+ public static DataBroker create(@Nonnull final ModifiableDataManager configDataTree,
+ @Nonnull final ReadableDataManager operationalDataTree) {
+ checkNotNull(operationalDataTree, "operationalDataTree should not be null");
+ checkNotNull(configDataTree, "configDataTree should not be null");
+ return new DataBroker(new MainPipelineTxFactory(configDataTree, operationalDataTree));
+ }
+
+ /**
+ * Create DataBroker for modifiable operational DT, but no support for config
+ */
+ @Nonnull
+ public static DataBroker create(@Nonnull final ModifiableDataManager operationalDataTree) {
+ checkNotNull(operationalDataTree, "operationalDataTree should not be null");
+ return new DataBroker(new ContextPipelineTxFactory(operationalDataTree));
+ }
+
+ @Override
+ public void close() throws IOException {
+ // NOOP
+ }
+
+ /**
+ * Transaction provider factory to be used by {@link DataBroker}
+ */
+ public interface TransactionFactory {
+
+ DOMDataReadOnlyTransaction newReadOnlyTransaction();
+
+ DOMDataReadWriteTransaction newReadWriteTransaction();
+
+ DOMDataWriteTransaction newWriteOnlyTransaction();
+ }
+
+ /**
+ * Transaction factory specific for Honeycomb's main pipeline (config: read+write, operational: read-only)
+ */
+ private static class MainPipelineTxFactory implements TransactionFactory {
+ private final ReadableDataManager operationalDataTree;
+ private final ModifiableDataManager configDataTree;
+
+ MainPipelineTxFactory(@Nonnull final ModifiableDataManager configDataTree,
+ @Nonnull final ReadableDataManager operationalDataTree) {
+ this.operationalDataTree = operationalDataTree;
+ this.configDataTree = configDataTree;
+ }
+
+ @Override
+ public DOMDataReadOnlyTransaction newReadOnlyTransaction() {
+ return ReadOnlyTransaction.create(configDataTree.newModification(), operationalDataTree);
+ }
+
+ @Override
+ public DOMDataReadWriteTransaction newReadWriteTransaction() {
+ final DataModification configModification = configDataTree.newModification();
+ return new ReadWriteTransaction(
+ ReadOnlyTransaction.create(configModification, operationalDataTree),
+ WriteTransaction.createConfigOnly(configModification));
+ }
+
+ @Override
+ public DOMDataWriteTransaction newWriteOnlyTransaction() {
+ return WriteTransaction.createConfigOnly(configDataTree.newModification());
+ }
+ }
+
+ /**
+ * Transaction factory specific for Honeycomb's context pipeline (config: none, operational: read+write)
+ */
+ private static class ContextPipelineTxFactory implements TransactionFactory {
+ private final ModifiableDataManager operationalDataTree;
+
+ ContextPipelineTxFactory(@Nonnull final ModifiableDataManager operationalDataTree) {
+ this.operationalDataTree = operationalDataTree;
+ }
+
+ @Override
+ public DOMDataReadOnlyTransaction newReadOnlyTransaction() {
+ return ReadOnlyTransaction.createOperationalOnly(operationalDataTree);
+ }
+
+ @Override
+ public DOMDataReadWriteTransaction newReadWriteTransaction() {
+ final DataModification dataModification = operationalDataTree.newModification();
+ return new ReadWriteTransaction(
+ ReadOnlyTransaction.createOperationalOnly(dataModification),
+ WriteTransaction.createOperationalOnly(dataModification));
+ }
+
+ @Override
+ public DOMDataWriteTransaction newWriteOnlyTransaction() {
+ return WriteTransaction.createOperationalOnly(operationalDataTree.newModification());
+ }
+ }
+}
+
+
diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegator.java b/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegator.java
new file mode 100644
index 0000000..2c2581e
--- /dev/null
+++ b/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegator.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.data.impl;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.util.concurrent.Futures.immediateCheckedFuture;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+import com.google.common.util.concurrent.CheckedFuture;
+import io.fd.honeycomb.v3po.data.DataModification;
+import io.fd.honeycomb.v3po.data.ReadableDataManager;
+import io.fd.honeycomb.v3po.translate.TranslationException;
+import io.fd.honeycomb.v3po.translate.util.RWUtils;
+import io.fd.honeycomb.v3po.translate.util.TransactionMappingContext;
+import io.fd.honeycomb.v3po.translate.util.write.TransactionWriteContext;
+import io.fd.honeycomb.v3po.translate.write.DataObjectUpdate;
+import io.fd.honeycomb.v3po.translate.write.WriteContext;
+import io.fd.honeycomb.v3po.translate.write.registry.WriterRegistry;
+import java.util.Map;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
+import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Extension of {@link ModifiableDataTreeManager} that propagates data changes to underlying writer layer before they
+ * are fully committed in the backing data tree. Data changes are propagated in BA format.
+ */
+public final class ModifiableDataTreeDelegator extends ModifiableDataTreeManager {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ModifiableDataTreeDelegator.class);
+ private static final ReadableDataManager EMPTY_OPERATIONAL = p -> immediateCheckedFuture(Optional.absent());
+
+ private final WriterRegistry writerRegistry;
+ private final org.opendaylight.controller.md.sal.binding.api.DataBroker contextBroker;
+ // TODO what to use instead of deprecated BindingNormalizedNodeSerializer ?
+ private final BindingNormalizedNodeSerializer serializer;
+
+ /**
+ * Creates configuration data tree instance.
+ * @param serializer service for serialization between Java Binding Data representation and NormalizedNode
+ * representation.
+ * @param dataTree data tree for configuration data representation
+ * @param writerRegistry service for translation between Java Binding Data and data provider, capable of performing
+ * @param contextBroker BA broker providing full access to mapping context data
+ */
+ public ModifiableDataTreeDelegator(@Nonnull final BindingNormalizedNodeSerializer serializer,
+ @Nonnull final DataTree dataTree,
+ @Nonnull final WriterRegistry writerRegistry,
+ @Nonnull final org.opendaylight.controller.md.sal.binding.api.DataBroker contextBroker) {
+ super(dataTree);
+ this.contextBroker = checkNotNull(contextBroker, "contextBroker should not be null");
+ this.serializer = checkNotNull(serializer, "serializer should not be null");
+ this.writerRegistry = checkNotNull(writerRegistry, "writerRegistry should not be null");
+ }
+
+ @Override
+ public DataModification newModification() {
+ return new ConfigSnapshot(super.newModification());
+ }
+
+ private final class ConfigSnapshot extends ModifiableDataTreeManager.ConfigSnapshot {
+
+ private final DataModification untouchedModification;
+
+ /**
+ * @param untouchedModification DataModification captured while this modification/snapshot was created.
+ * To be used later while invoking writers to provide them with before state
+ * (state without current modifications).
+ * It must be captured as close as possible to when current modification started.
+ */
+ ConfigSnapshot(final DataModification untouchedModification) {
+ this.untouchedModification = untouchedModification;
+ }
+
+ /**
+ * Pass the changes to underlying writer layer.
+ * Transform from BI to BA.
+ * Revert(Write data before to subtrees that have been successfully modified before failure) in case of failure.
+ */
+ @Override
+ protected void processCandidate(final DataTreeCandidate candidate)
+ throws TranslationException {
+
+ final DataTreeCandidateNode rootNode = candidate.getRootNode();
+ final YangInstanceIdentifier rootPath = candidate.getRootPath();
+ LOG.trace("ConfigDataTree.modify() rootPath={}, rootNode={}, dataBefore={}, dataAfter={}",
+ rootPath, rootNode, rootNode.getDataBefore(), rootNode.getDataAfter());
+
+ final ModificationDiff modificationDiff =
+ ModificationDiff.recursivelyFromCandidate(YangInstanceIdentifier.EMPTY, rootNode);
+ LOG.debug("ConfigDataTree.modify() diff: {}", modificationDiff);
+
+ // Distinguish between updates (create + update) and deletes
+ final WriterRegistry.DataObjectUpdates baUpdates = toBindingAware(modificationDiff.getUpdates());
+ LOG.debug("ConfigDataTree.modify() extracted updates={}", baUpdates);
+
+ try (final WriteContext ctx = getTransactionWriteContext()) {
+ writerRegistry.update(baUpdates, ctx);
+
+ final CheckedFuture<Void, TransactionCommitFailedException> contextUpdateResult =
+ ((TransactionMappingContext) ctx.getMappingContext()).submit();
+ // Blocking on context data update
+ contextUpdateResult.checkedGet();
+
+ } catch (WriterRegistry.BulkUpdateException e) {
+ LOG.warn("Failed to apply all changes", e);
+ LOG.info("Trying to revert successful changes for current transaction");
+
+ try {
+ e.revertChanges();
+ LOG.info("Changes successfully reverted");
+ } catch (WriterRegistry.Reverter.RevertFailedException revertFailedException) {
+ // fail with failed revert
+ LOG.error("Failed to revert successful changes", revertFailedException);
+ throw revertFailedException;
+ }
+
+ throw e; // fail with success revert
+ } catch (TransactionCommitFailedException e) {
+ // FIXME revert should probably occur when context is not written successfully
+ final String msg = "Error while updating mapping context data";
+ LOG.error(msg, e);
+ throw new TranslationException(msg, e);
+ } catch (TranslationException e) {
+ LOG.error("Error while processing data change (updates={})", baUpdates, e);
+ throw e;
+ }
+ }
+
+ private TransactionWriteContext getTransactionWriteContext() {
+ // Before Tx must use modification
+ final DOMDataReadOnlyTransaction beforeTx = ReadOnlyTransaction.create(untouchedModification, EMPTY_OPERATIONAL);
+ // After Tx must use current modification
+ final DOMDataReadOnlyTransaction afterTx = ReadOnlyTransaction.create(this, EMPTY_OPERATIONAL);
+ final TransactionMappingContext mappingContext = new TransactionMappingContext(
+ contextBroker.newReadWriteTransaction());
+ return new TransactionWriteContext(serializer, beforeTx, afterTx, mappingContext);
+ }
+
+ private WriterRegistry.DataObjectUpdates toBindingAware(
+ final Map<YangInstanceIdentifier, ModificationDiff.NormalizedNodeUpdate> biNodes) {
+ return ModifiableDataTreeDelegator.toBindingAware(biNodes, serializer);
+ }
+ }
+
+ @VisibleForTesting
+ static WriterRegistry.DataObjectUpdates toBindingAware(
+ final Map<YangInstanceIdentifier, ModificationDiff.NormalizedNodeUpdate> biNodes,
+ final BindingNormalizedNodeSerializer serializer) {
+
+ final Multimap<InstanceIdentifier<?>, DataObjectUpdate> dataObjectUpdates = HashMultimap.create();
+ final Multimap<InstanceIdentifier<?>, DataObjectUpdate.DataObjectDelete> dataObjectDeletes =
+ HashMultimap.create();
+
+ for (Map.Entry<YangInstanceIdentifier, ModificationDiff.NormalizedNodeUpdate> biEntry : biNodes.entrySet()) {
+ final InstanceIdentifier<?> unkeyedIid =
+ RWUtils.makeIidWildcarded(serializer.fromYangInstanceIdentifier(biEntry.getKey()));
+
+ ModificationDiff.NormalizedNodeUpdate normalizedNodeUpdate = biEntry.getValue();
+ final DataObjectUpdate dataObjectUpdate = toDataObjectUpdate(normalizedNodeUpdate, serializer);
+ if (dataObjectUpdate != null) {
+ if (dataObjectUpdate instanceof DataObjectUpdate.DataObjectDelete) {
+ dataObjectDeletes.put(unkeyedIid, ((DataObjectUpdate.DataObjectDelete) dataObjectUpdate));
+ } else {
+ dataObjectUpdates.put(unkeyedIid, dataObjectUpdate);
+ }
+ }
+ }
+ return new WriterRegistry.DataObjectUpdates(dataObjectUpdates, dataObjectDeletes);
+ }
+
+ @Nullable
+ private static DataObjectUpdate toDataObjectUpdate(
+ final ModificationDiff.NormalizedNodeUpdate normalizedNodeUpdate,
+ final BindingNormalizedNodeSerializer serializer) {
+
+ InstanceIdentifier<?> baId = serializer.fromYangInstanceIdentifier(normalizedNodeUpdate.getId());
+ checkNotNull(baId, "Unable to transform instance identifier: %s into BA", normalizedNodeUpdate.getId());
+
+ DataObject dataObjectBefore = getDataObject(serializer,
+ normalizedNodeUpdate.getDataBefore(), normalizedNodeUpdate.getId());
+ DataObject dataObjectAfter =
+ getDataObject(serializer, normalizedNodeUpdate.getDataAfter(), normalizedNodeUpdate.getId());
+
+ return dataObjectBefore == null && dataObjectAfter == null
+ ? null
+ : DataObjectUpdate.create(baId, dataObjectBefore, dataObjectAfter);
+ }
+
+ @Nullable
+ private static DataObject getDataObject(@Nonnull final BindingNormalizedNodeSerializer serializer,
+ @Nullable final NormalizedNode<?, ?> data,
+ @Nonnull final YangInstanceIdentifier id) {
+ DataObject dataObject = null;
+ if (data != null) {
+ final Map.Entry<InstanceIdentifier<?>, DataObject> dataObjectEntry =
+ serializer.fromNormalizedNode(id, data);
+ if (dataObjectEntry != null) {
+ dataObject = dataObjectEntry.getValue();
+ }
+ }
+ return dataObject;
+ }
+
+}
+
+
+
diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeManager.java b/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeManager.java
new file mode 100644
index 0000000..1082c47
--- /dev/null
+++ b/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeManager.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.data.impl;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.util.concurrent.Futures.immediateCheckedFuture;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import io.fd.honeycomb.v3po.data.DataModification;
+import io.fd.honeycomb.v3po.data.ModifiableDataManager;
+import io.fd.honeycomb.v3po.translate.TranslationException;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * DataTree backed implementation for modifiable data manager.
+ */
+public class ModifiableDataTreeManager implements ModifiableDataManager {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ModifiableDataTreeManager.class);
+
+ private final DataTree dataTree;
+
+ public ModifiableDataTreeManager(@Nonnull final DataTree dataTree) {
+ this.dataTree = checkNotNull(dataTree, "dataTree should not be null");
+ }
+
+ @Override
+ public DataModification newModification() {
+ return new ConfigSnapshot();
+ }
+
+ @Override
+ public final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(@Nonnull final YangInstanceIdentifier path) {
+ return newModification().read(path);
+ }
+
+ protected class ConfigSnapshot implements DataModification {
+ private final DataTreeModification modification;
+ private boolean validated = false;
+
+ ConfigSnapshot() {
+ this(dataTree.takeSnapshot().newModification());
+ }
+
+ protected ConfigSnapshot(final DataTreeModification modification) {
+ this.modification = modification;
+ }
+
+ @Override
+ public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(
+ @Nonnull final YangInstanceIdentifier path) {
+ final Optional<NormalizedNode<?, ?>> node = modification.readNode(path);
+ if (LOG.isTraceEnabled() && node.isPresent()) {
+ LOG.trace("ConfigSnapshot.read: {}", node.get());
+ }
+ return immediateCheckedFuture(node);
+ }
+
+ @Override
+ public final void delete(final YangInstanceIdentifier path) {
+ modification.delete(path);
+ }
+
+ @Override
+ public final void merge(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
+ modification.merge(path, data);
+ }
+
+ @Override
+ public final void write(final YangInstanceIdentifier path, final NormalizedNode<?, ?> data) {
+ modification.write(path, data);
+ }
+
+ @Override
+ public final void commit() throws DataValidationFailedException, TranslationException {
+ if(!validated) {
+ validate();
+ }
+ final DataTreeCandidate candidate = dataTree.prepare(modification);
+ processCandidate(candidate);
+ dataTree.commit(candidate);
+ }
+
+ protected void processCandidate(final DataTreeCandidate candidate) throws TranslationException {
+ // NOOP
+ }
+
+ @Override
+ public final void validate() throws DataValidationFailedException {
+ modification.ready();
+ dataTree.validate(modification);
+ validated = true;
+ }
+ }
+}
+
+
+
diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModificationDiff.java b/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModificationDiff.java
new file mode 100644
index 0000000..abc0062
--- /dev/null
+++ b/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ModificationDiff.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.data.impl;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.collect.ImmutableMap;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MixinNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
+
+/**
+ * Recursively collects and provides all unique and non-null modifications (modified normalized nodes).
+ */
+final class ModificationDiff {
+
+ private static final ModificationDiff EMPTY_DIFF = new ModificationDiff(Collections.emptyMap());
+ private static final EnumSet LEAF_MODIFICATIONS = EnumSet.of(ModificationType.WRITE, ModificationType.DELETE);
+
+ private final Map<YangInstanceIdentifier, NormalizedNodeUpdate> updates;
+
+ private ModificationDiff(@Nonnull Map<YangInstanceIdentifier, NormalizedNodeUpdate> updates) {
+ this.updates = updates;
+ }
+
+ /**
+ * Get processed modifications.
+ *
+ * @return mapped modifications, where key is keyed {@link YangInstanceIdentifier}.
+ */
+ Map<YangInstanceIdentifier, NormalizedNodeUpdate> getUpdates() {
+ return updates;
+ }
+
+ private ModificationDiff merge(final ModificationDiff other) {
+ if (this == EMPTY_DIFF) {
+ return other;
+ }
+
+ if (other == EMPTY_DIFF) {
+ return this;
+ }
+
+ return new ModificationDiff(join(updates, other.updates));
+ }
+
+ private static Map<YangInstanceIdentifier, NormalizedNodeUpdate> join(Map<YangInstanceIdentifier, NormalizedNodeUpdate> first,
+ Map<YangInstanceIdentifier, NormalizedNodeUpdate> second) {
+ final Map<YangInstanceIdentifier, NormalizedNodeUpdate> merged = new HashMap<>();
+ merged.putAll(first);
+ merged.putAll(second);
+ return merged;
+ }
+
+ private static ModificationDiff create(YangInstanceIdentifier id, DataTreeCandidateNode candidate) {
+ return new ModificationDiff(ImmutableMap.of(id, NormalizedNodeUpdate.create(id, candidate)));
+ }
+
+ /**
+ * Produce an aggregated diff from a candidate node recursively. MixinNodes are ignored as modifications and so
+ * are complex nodes which direct leaves were not modified.
+ */
+ @Nonnull
+ static ModificationDiff recursivelyFromCandidate(@Nonnull final YangInstanceIdentifier yangIid,
+ @Nonnull final DataTreeCandidateNode currentCandidate) {
+ // recursively process child nodes for exact modifications
+ return recursivelyChildrenFromCandidate(yangIid, currentCandidate)
+ // also add modification on current level, if elligible
+ .merge(isModification(currentCandidate)
+ ? ModificationDiff.create(yangIid, currentCandidate)
+ : EMPTY_DIFF);
+ }
+
+ /**
+ * Check whether current node was modified. {@link MixinNode}s are ignored
+ * and only nodes which direct leaves(or choices) are modified are considered a modification.
+ */
+ private static Boolean isModification(@Nonnull final DataTreeCandidateNode currentCandidate) {
+ // Mixin nodes are not considered modifications
+ if (isMixin(currentCandidate) && !isAugment(currentCandidate)) {
+ return false;
+ } else {
+ return isCurrentModified(currentCandidate);
+ }
+ }
+
+ private static Boolean isCurrentModified(final @Nonnull DataTreeCandidateNode currentCandidate) {
+ // Check if there are any modified leaves and if so, consider current node as modified
+ final Boolean directLeavesModified = currentCandidate.getChildNodes().stream()
+ .filter(ModificationDiff::isLeaf)
+ // For some reason, we get modifications on unmodified list keys TODO debug and report ODL bug
+ // and that messes up our modifications collection here, so we need to skip
+ .filter(ModificationDiff::isBeforeAndAfterDifferent)
+ .filter(child -> LEAF_MODIFICATIONS.contains(child.getModificationType()))
+ .findFirst()
+ .isPresent();
+
+ return directLeavesModified
+ // Also check choices (choices do not exist in BA world and if anything within a choice was modified,
+ // consider its parent as being modified)
+ || currentCandidate.getChildNodes().stream()
+ .filter(ModificationDiff::isChoice)
+ // Recursively check each choice if there was any change to it
+ .filter(ModificationDiff::isCurrentModified)
+ .findFirst()
+ .isPresent();
+ }
+
+ /**
+ * Process all non-leaf child nodes recursively, creating aggregated {@link ModificationDiff}.
+ */
+ private static ModificationDiff recursivelyChildrenFromCandidate(final @Nonnull YangInstanceIdentifier yangIid,
+ final @Nonnull DataTreeCandidateNode currentCandidate) {
+ // recursively process child nodes for specific modifications
+ return currentCandidate.getChildNodes().stream()
+ // not interested in modifications to leaves
+ .filter(child -> !isLeaf(child))
+ .map(candidate -> recursivelyFromCandidate(yangIid.node(candidate.getIdentifier()), candidate))
+ .reduce(ModificationDiff::merge)
+ .orElse(EMPTY_DIFF);
+ }
+
+ /**
+ * Check whether candidate.before and candidate.after is different. If not return false.
+ */
+ private static boolean isBeforeAndAfterDifferent(@Nonnull final DataTreeCandidateNode candidateNode) {
+ if (candidateNode.getDataBefore().isPresent()) {
+ return !candidateNode.getDataBefore().get().equals(candidateNode.getDataAfter().orNull());
+ }
+
+ // considering not a modification if data after is also null
+ return candidateNode.getDataAfter().isPresent();
+ }
+
+ /**
+ * Check whether candidate node is for a leaf type node.
+ */
+ private static boolean isLeaf(final DataTreeCandidateNode candidateNode) {
+ // orNull intentional, some candidate nodes have both data after and data before null
+ return candidateNode.getDataAfter().orNull() instanceof LeafNode<?>
+ || candidateNode.getDataBefore().orNull() instanceof LeafNode<?>;
+ }
+
+ /**
+ * Check whether candidate node is for a Mixin type node.
+ */
+ private static boolean isMixin(final DataTreeCandidateNode candidateNode) {
+ // orNull intentional, some candidate nodes have both data after and data before null
+ return candidateNode.getDataAfter().orNull() instanceof MixinNode
+ || candidateNode.getDataBefore().orNull() instanceof MixinNode;
+ }
+
+ /**
+ * Check whether candidate node is for an Augmentation type node.
+ */
+ private static boolean isAugment(final DataTreeCandidateNode candidateNode) {
+ // orNull intentional, some candidate nodes have both data after and data before null
+ return candidateNode.getDataAfter().orNull() instanceof AugmentationNode
+ || candidateNode.getDataBefore().orNull() instanceof AugmentationNode;
+ }
+
+ /**
+ * Check whether candidate node is for a Choice type node.
+ */
+ private static boolean isChoice(final DataTreeCandidateNode candidateNode) {
+ // orNull intentional, some candidate nodes have both data after and data before null
+ return candidateNode.getDataAfter().orNull() instanceof ChoiceNode
+ || candidateNode.getDataBefore().orNull() instanceof ChoiceNode;
+ }
+
+ @Override
+ public String toString() {
+ return "ModificationDiff{updates=" + updates + '}';
+ }
+
+ /**
+ * Update to a normalized node identifiable by its {@link YangInstanceIdentifier}.
+ */
+ static final class NormalizedNodeUpdate {
+
+ @Nonnull
+ private final YangInstanceIdentifier id;
+ @Nullable
+ private final NormalizedNode<?, ?> dataBefore;
+ @Nullable
+ private final NormalizedNode<?, ?> dataAfter;
+
+ private NormalizedNodeUpdate(@Nonnull final YangInstanceIdentifier id,
+ @Nullable final NormalizedNode<?, ?> dataBefore,
+ @Nullable final NormalizedNode<?, ?> dataAfter) {
+ this.id = checkNotNull(id);
+ this.dataAfter = dataAfter;
+ this.dataBefore = dataBefore;
+ }
+
+ @Nullable
+ public NormalizedNode<?, ?> getDataBefore() {
+ return dataBefore;
+ }
+
+ @Nullable
+ public NormalizedNode<?, ?> getDataAfter() {
+ return dataAfter;
+ }
+
+ @Nonnull
+ public YangInstanceIdentifier getId() {
+ return id;
+ }
+
+ static NormalizedNodeUpdate create(@Nonnull final YangInstanceIdentifier id,
+ @Nonnull final DataTreeCandidateNode candidate) {
+ return create(id, candidate.getDataBefore().orNull(), candidate.getDataAfter().orNull());
+ }
+
+ static NormalizedNodeUpdate create(@Nonnull final YangInstanceIdentifier id,
+ @Nullable final NormalizedNode<?, ?> dataBefore,
+ @Nullable final NormalizedNode<?, ?> dataAfter) {
+ checkArgument(!(dataBefore == null && dataAfter == null), "Both before and after data are null");
+ return new NormalizedNodeUpdate(id, dataBefore, dataAfter);
+ }
+
+ @Override
+ public boolean equals(final Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (other == null || getClass() != other.getClass()) {
+ return false;
+ }
+
+ final NormalizedNodeUpdate that = (NormalizedNodeUpdate) other;
+
+ return id.equals(that.id);
+
+ }
+
+ @Override
+ public int hashCode() {
+ return id.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "NormalizedNodeUpdate{" + "id=" + id
+ + ", dataBefore=" + dataBefore
+ + ", dataAfter=" + dataAfter
+ + '}';
+ }
+ }
+
+}
diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapter.java b/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapter.java
new file mode 100644
index 0000000..9b71dfd
--- /dev/null
+++ b/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapter.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.data.impl;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.v3po.translate.util.JsonUtils;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.sal.core.api.model.SchemaService;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Adapter for a DataTree that stores current state of data in backing DataTree on each successful commit.
+ * Uses JSON format.
+ */
+public class PersistingDataTreeAdapter implements DataTree, AutoCloseable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(PersistingDataTreeAdapter.class);
+
+ private final DataTree delegateDependency;
+ private final SchemaService schemaServiceDependency;
+ private final Path path;
+
+ /**
+ * Create new Persisting DataTree adapter
+ *
+ * @param delegate backing data tree that actually handles all the operations
+ * @param persistPath path to a file (existing or not) to be used as storage for persistence. Full control over
+ * a file at peristPath is expected
+ * @param schemaService schemaContext provier
+ */
+ public PersistingDataTreeAdapter(@Nonnull final DataTree delegate,
+ @Nonnull final SchemaService schemaService,
+ @Nonnull final Path persistPath) {
+ this.path = testPersistPath(checkNotNull(persistPath, "persistPath is null"));
+ this.delegateDependency = checkNotNull(delegate, "delegate is null");
+ this.schemaServiceDependency = checkNotNull(schemaService, "schemaService is null");
+ }
+
+ /**
+ * Test whether file at persistPath exists and is readable or create it along with its parent structure
+ */
+ private Path testPersistPath(final Path persistPath) {
+ try {
+ checkArgument(!Files.isDirectory(persistPath), "Path %s points to a directory", persistPath);
+ if(Files.exists(persistPath)) {
+ checkArgument(Files.isReadable(persistPath),
+ "Provided path %s points to existing, but non-readable file", persistPath);
+ return persistPath;
+ }
+ Files.createDirectories(persistPath.getParent());
+ Files.write(persistPath, new byte[]{}, StandardOpenOption.CREATE);
+ } catch (IOException | UnsupportedOperationException e) {
+ LOG.warn("Provided path for persistence: {} is not usable", persistPath, e);
+ throw new IllegalArgumentException("Path " + persistPath + " cannot be used as ");
+ }
+
+ return persistPath;
+ }
+
+ @Override
+ public DataTreeSnapshot takeSnapshot() {
+ return delegateDependency.takeSnapshot();
+ }
+
+ @Override
+ public void setSchemaContext(final SchemaContext schemaContext) {
+ delegateDependency.setSchemaContext(schemaContext);
+ }
+
+ @Override
+ public void commit(final DataTreeCandidate dataTreeCandidate) {
+ LOG.trace("Commit detected");
+ delegateDependency.commit(dataTreeCandidate);
+ LOG.debug("Delegate commit successful. Persisting data");
+
+ // FIXME doing full read and full write might not be the fastest way of persisting data here
+ final DataTreeSnapshot dataTreeSnapshot = delegateDependency.takeSnapshot();
+
+ // TODO this can be handled in background by a dedicated thread + a limited blocking queue
+ // TODO enable configurable granularity for persists. Maybe doing write on every modification is too much
+ // and we could do bulk persist
+ persistCurrentData(dataTreeSnapshot.readNode(YangInstanceIdentifier.EMPTY));
+ }
+
+ private void persistCurrentData(final Optional<NormalizedNode<?, ?>> currentRoot) {
+ if(currentRoot.isPresent()) {
+ try {
+ LOG.trace("Persisting current data: {} into: {}", currentRoot.get(), path);
+ JsonUtils.writeJsonRoot(currentRoot.get(), schemaServiceDependency.getGlobalContext(),
+ Files.newOutputStream(path, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING));
+ LOG.trace("Data persisted successfully in {}", path);
+ } catch (IOException e) {
+ throw new IllegalStateException("Unable to persist current data", e);
+ }
+ } else {
+ LOG.debug("Skipping persistence, since there's no data to persist");
+ }
+ }
+
+ @Override
+ public YangInstanceIdentifier getRootPath() {
+ return delegateDependency.getRootPath();
+ }
+
+ @Override
+ public void validate(final DataTreeModification dataTreeModification) throws DataValidationFailedException {
+ delegateDependency.validate(dataTreeModification);
+ }
+
+ @Override
+ public DataTreeCandidate prepare(
+ final DataTreeModification dataTreeModification) {
+ return delegateDependency.prepare(dataTreeModification);
+ }
+
+ @Override
+ public void close() throws Exception {
+ LOG.trace("Closing {} for {}", getClass().getSimpleName(), path);
+ // NOOP
+ }
+}
diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransaction.java b/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransaction.java
new file mode 100644
index 0000000..2850a0d
--- /dev/null
+++ b/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransaction.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.data.impl;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import io.fd.honeycomb.v3po.data.ReadableDataManager;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class ReadOnlyTransaction implements DOMDataReadOnlyTransaction {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ReadOnlyTransaction.class);
+
+ @Nullable
+ private ReadableDataManager operationalData;
+ @Nullable
+ private ReadableDataManager configSnapshot;
+
+ private boolean closed = false;
+
+ /**
+ * @param configData config data tree manager. Null if config reads are not to be supported
+ * @param operationalData operational data tree manager. Null if operational reads are not to be supported
+ */
+ private ReadOnlyTransaction(@Nullable final ReadableDataManager configData,
+ @Nullable final ReadableDataManager operationalData) {
+ this.configSnapshot = configData;
+ this.operationalData = operationalData;
+ }
+
+ @Override
+ public synchronized void close() {
+ closed = true;
+ configSnapshot = null;
+ operationalData = null;
+ }
+
+ @Override
+ public synchronized CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(
+ final LogicalDatastoreType store,
+ final YangInstanceIdentifier path) {
+ LOG.debug("ReadOnlyTransaction.read(), store={}, path={}", store, path);
+ checkState(!closed, "Transaction has been closed");
+
+ if (store == LogicalDatastoreType.OPERATIONAL) {
+ checkArgument(operationalData != null, "{} reads not supported", store);
+ return operationalData.read(path);
+ } else {
+ checkArgument(configSnapshot != null, "{} reads not supported", store);
+ return configSnapshot.read(path);
+ }
+ }
+
+ @Override
+ public CheckedFuture<Boolean, ReadFailedException> exists(final LogicalDatastoreType store,
+ final YangInstanceIdentifier path) {
+ LOG.debug("ReadOnlyTransaction.exists() store={}, path={}", store, path);
+
+ ListenableFuture<Boolean> listenableFuture = Futures.transform(read(store, path), IS_NODE_PRESENT);
+ return Futures.makeChecked(listenableFuture, ANY_EX_TO_READ_FAILED_EXCEPTION_MAPPER);
+ }
+
+ @Nonnull
+ @Override
+ public Object getIdentifier() {
+ return this;
+ }
+
+ @Nonnull
+ static ReadOnlyTransaction createOperationalOnly(@Nonnull final ReadableDataManager operationalData) {
+ return new ReadOnlyTransaction(null, requireNonNull(operationalData));
+ }
+
+ @Nonnull
+ static ReadOnlyTransaction createConfigOnly(@Nonnull final ReadableDataManager configData) {
+ return new ReadOnlyTransaction(requireNonNull(configData), null);
+ }
+
+ @Nonnull
+ static ReadOnlyTransaction create(@Nonnull final ReadableDataManager configData,
+ @Nonnull final ReadableDataManager operationalData) {
+ return new ReadOnlyTransaction(requireNonNull(configData), requireNonNull(operationalData));
+ }
+
+ private static final Function<? super Optional<NormalizedNode<?, ?>>, ? extends Boolean> IS_NODE_PRESENT =
+ (Function<Optional<NormalizedNode<?, ?>>, Boolean>) input -> input == null ? Boolean.FALSE : input.isPresent();
+
+ private static final Function<? super Exception, ReadFailedException> ANY_EX_TO_READ_FAILED_EXCEPTION_MAPPER =
+ (Function<Exception, ReadFailedException>) e -> new ReadFailedException("Exists failed", e);
+} \ No newline at end of file
diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadWriteTransaction.java b/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadWriteTransaction.java
new file mode 100644
index 0000000..88b4643
--- /dev/null
+++ b/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadWriteTransaction.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.data.impl;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.ListenableFuture;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+/**
+ * Composite DOM transaction that delegates reads to a {@link DOMDataReadTransaction} delegate and writes to a {@link
+ * DOMDataWriteTransaction} delegate.
+ */
+final class ReadWriteTransaction implements DOMDataReadWriteTransaction {
+
+ private final DOMDataReadOnlyTransaction delegateReadTx;
+ private final DOMDataWriteTransaction delegateWriteTx;
+
+ ReadWriteTransaction(@Nonnull final DOMDataReadOnlyTransaction delegateReadTx,
+ @Nonnull final DOMDataWriteTransaction delegateWriteTx) {
+ this.delegateReadTx = Preconditions.checkNotNull(delegateReadTx, "delegateReadTx should not be null");
+ this.delegateWriteTx = Preconditions.checkNotNull(delegateWriteTx, "delegateWriteTx should not be null");
+ }
+
+ @Override
+ public boolean cancel() {
+ delegateReadTx.close();
+ return delegateWriteTx.cancel();
+ }
+
+ @Override
+ public void put(final LogicalDatastoreType store, final YangInstanceIdentifier path,
+ final NormalizedNode<?, ?> data) {
+ delegateWriteTx.put(store, path, data);
+ }
+
+ @Override
+ public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path,
+ final NormalizedNode<?, ?> data) {
+ delegateWriteTx.merge(store, path, data);
+ }
+
+ @Override
+ public void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+ delegateWriteTx.delete(store, path);
+ }
+
+ @Override
+ public CheckedFuture<Void, TransactionCommitFailedException> submit() {
+ return delegateWriteTx.submit();
+ }
+
+ @Override
+ public ListenableFuture<RpcResult<TransactionStatus>> commit() {
+ return delegateWriteTx.commit();
+ }
+
+ @Override
+ public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(final LogicalDatastoreType store,
+ final YangInstanceIdentifier path) {
+ return delegateReadTx.read(store, path);
+ }
+
+ @Override
+ public CheckedFuture<Boolean, ReadFailedException> exists(final LogicalDatastoreType store,
+ final YangInstanceIdentifier path) {
+ return delegateReadTx.exists(store, path);
+ }
+
+ @Override
+ public Object getIdentifier() {
+ return this;
+ }
+}
+
diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadableDataTreeDelegator.java b/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadableDataTreeDelegator.java
new file mode 100644
index 0000000..aff023e
--- /dev/null
+++ b/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadableDataTreeDelegator.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.data.impl;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.getOnlyElement;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Multimap;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import io.fd.honeycomb.v3po.data.ReadableDataManager;
+import io.fd.honeycomb.v3po.translate.MappingContext;
+import io.fd.honeycomb.v3po.translate.ModificationCache;
+import io.fd.honeycomb.v3po.translate.read.ReadContext;
+import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
+import io.fd.honeycomb.v3po.translate.read.registry.ReaderRegistry;
+import io.fd.honeycomb.v3po.translate.util.TransactionMappingContext;
+import java.util.Collection;
+import java.util.Map;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * ReadableDataTree implementation for operational data.
+ */
+public final class ReadableDataTreeDelegator implements ReadableDataManager {
+ private static final Logger LOG = LoggerFactory.getLogger(ReadableDataTreeDelegator.class);
+
+ private final BindingNormalizedNodeSerializer serializer;
+ private final ReaderRegistry readerRegistry;
+ private final SchemaContext globalContext;
+ private final org.opendaylight.controller.md.sal.binding.api.DataBroker contextBroker;
+
+ /**
+ * Creates operational data tree instance.
+ * @param serializer service for serialization between Java Binding Data representation and NormalizedNode
+ * representation.
+ * @param globalContext service for obtaining top level context data from all yang modules.
+ * @param readerRegistry service responsible for translation between DataObjects and data provider.
+ * @param contextBroker BA broker for context data
+ */
+ public ReadableDataTreeDelegator(@Nonnull BindingNormalizedNodeSerializer serializer,
+ @Nonnull final SchemaContext globalContext,
+ @Nonnull final ReaderRegistry readerRegistry,
+ @Nonnull final org.opendaylight.controller.md.sal.binding.api.DataBroker contextBroker) {
+ this.contextBroker = checkNotNull(contextBroker, "contextBroker should not be null");
+ this.globalContext = checkNotNull(globalContext, "globalContext should not be null");
+ this.serializer = checkNotNull(serializer, "serializer should not be null");
+ this.readerRegistry = checkNotNull(readerRegistry, "reader should not be null");
+ }
+
+ @Override
+ public CheckedFuture<Optional<NormalizedNode<?, ?>>,
+ org.opendaylight.controller.md.sal.common.api.data.ReadFailedException> read(
+ @Nonnull final YangInstanceIdentifier yangInstanceIdentifier) {
+
+ try(TransactionMappingContext mappingContext = new TransactionMappingContext(contextBroker.newReadWriteTransaction());
+ ReadContext ctx = new ReadContextImpl(mappingContext)) {
+
+ final Optional<NormalizedNode<?, ?>> value;
+ if (checkNotNull(yangInstanceIdentifier).equals(YangInstanceIdentifier.EMPTY)) {
+ value = readRoot(ctx);
+ } else {
+ value = readNode(yangInstanceIdentifier, ctx);
+ }
+
+ // Submit context mapping updates
+ final CheckedFuture<Void, TransactionCommitFailedException> contextUpdateResult =
+ ((TransactionMappingContext) ctx.getMappingContext()).submit();
+ // Blocking on context data update
+ contextUpdateResult.checkedGet();
+
+ return Futures.immediateCheckedFuture(value);
+
+ } catch (ReadFailedException e) {
+ return Futures.immediateFailedCheckedFuture(
+ new org.opendaylight.controller.md.sal.common.api.data.ReadFailedException(
+ "Failed to read VPP data", e));
+ } catch (TransactionCommitFailedException e) {
+ // FIXME revert should probably occur when context is not written successfully
+ final String msg = "Error while updating mapping context data";
+ LOG.error(msg, e);
+ return Futures.immediateFailedCheckedFuture(
+ new org.opendaylight.controller.md.sal.common.api.data.ReadFailedException(msg, e)
+ );
+ }
+ }
+
+ private Optional<NormalizedNode<?, ?>> readNode(final YangInstanceIdentifier yangInstanceIdentifier,
+ final ReadContext ctx) throws ReadFailedException {
+ LOG.debug("OperationalDataTree.readNode(), yangInstanceIdentifier={}", yangInstanceIdentifier);
+ final InstanceIdentifier<?> path = serializer.fromYangInstanceIdentifier(yangInstanceIdentifier);
+ checkNotNull(path, "Invalid instance identifier %s. Cannot create BA equivalent.", yangInstanceIdentifier);
+ LOG.debug("OperationalDataTree.readNode(), path={}", path);
+
+ final Optional<? extends DataObject> dataObject;
+
+ dataObject = readerRegistry.read(path, ctx);
+ if (dataObject.isPresent()) {
+ final NormalizedNode<?, ?> value = toNormalizedNodeFunction(path).apply(dataObject.get());
+ return Optional.<NormalizedNode<?, ?>>fromNullable(value);
+ } else {
+ return Optional.absent();
+ }
+ }
+
+ private Optional<NormalizedNode<?, ?>> readRoot(final ReadContext ctx) throws ReadFailedException {
+ LOG.debug("OperationalDataTree.readRoot()");
+
+ final DataContainerNodeAttrBuilder<YangInstanceIdentifier.NodeIdentifier, ContainerNode> dataNodeBuilder =
+ Builders.containerBuilder()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(SchemaContext.NAME));
+
+ final Multimap<InstanceIdentifier<? extends DataObject>, ? extends DataObject> dataObjects =
+ readerRegistry.readAll(ctx);
+
+ for (final InstanceIdentifier<? extends DataObject> instanceIdentifier : dataObjects.keySet()) {
+ final YangInstanceIdentifier rootElementId = serializer.toYangInstanceIdentifier(instanceIdentifier);
+ final NormalizedNode<?, ?> node =
+ wrapDataObjects(rootElementId, instanceIdentifier, dataObjects.get(instanceIdentifier));
+ dataNodeBuilder.withChild((DataContainerChild<?, ?>) node);
+ }
+ return Optional.<NormalizedNode<?, ?>>of(dataNodeBuilder.build());
+ }
+
+ private NormalizedNode<?, ?> wrapDataObjects(final YangInstanceIdentifier yangInstanceIdentifier,
+ final InstanceIdentifier<? extends DataObject> instanceIdentifier,
+ final Collection<? extends DataObject> dataObjects) {
+ final Collection<NormalizedNode<?, ?>> normalizedRootElements = Collections2
+ .transform(dataObjects, toNormalizedNodeFunction(instanceIdentifier));
+
+ final DataSchemaNode schemaNode =
+ globalContext.getDataChildByName(yangInstanceIdentifier.getLastPathArgument().getNodeType());
+ if (schemaNode instanceof ListSchemaNode) {
+ // In case of a list, wrap all the values in a Mixin parent node
+ final ListSchemaNode listSchema = (ListSchemaNode) schemaNode;
+ return wrapListIntoMixinNode(normalizedRootElements, listSchema);
+ } else {
+ Preconditions.checkState(dataObjects.size() == 1, "Singleton list was expected");
+ return getOnlyElement(normalizedRootElements);
+ }
+ }
+
+ private static DataContainerChild<?, ?> wrapListIntoMixinNode(
+ final Collection<NormalizedNode<?, ?>> normalizedRootElements, final ListSchemaNode listSchema) {
+ if (listSchema.getKeyDefinition().isEmpty()) {
+ final CollectionNodeBuilder<UnkeyedListEntryNode, UnkeyedListNode> listBuilder =
+ Builders.unkeyedListBuilder();
+ for (NormalizedNode<?, ?> normalizedRootElement : normalizedRootElements) {
+ listBuilder.withChild((UnkeyedListEntryNode) normalizedRootElement);
+ }
+ return listBuilder.build();
+ } else {
+ final CollectionNodeBuilder<MapEntryNode, ? extends MapNode> listBuilder =
+ listSchema.isUserOrdered()
+ ? Builders.orderedMapBuilder()
+ : Builders.mapBuilder();
+
+ for (NormalizedNode<?, ?> normalizedRootElement : normalizedRootElements) {
+ listBuilder.withChild((MapEntryNode) normalizedRootElement);
+ }
+ return listBuilder.build();
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private Function<DataObject, NormalizedNode<?, ?>> toNormalizedNodeFunction(final InstanceIdentifier path) {
+ return dataObject -> {
+ LOG.trace("OperationalDataTree.toNormalizedNode(), path={}, dataObject={}", path, dataObject);
+ final Map.Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> entry =
+ serializer.toNormalizedNode(path, dataObject);
+
+ LOG.trace("OperationalDataTree.toNormalizedNode(), normalizedNodeEntry={}", entry);
+ return entry.getValue();
+ };
+ }
+
+ private static final class ReadContextImpl implements ReadContext {
+
+ private final ModificationCache ctx = new ModificationCache();
+ private final MappingContext mappingContext;
+
+ private ReadContextImpl(final MappingContext mappingContext) {
+ this.mappingContext = mappingContext;
+ }
+
+ @Nonnull
+ @Override
+ public ModificationCache getModificationCache() {
+ return ctx;
+ }
+
+ @Nonnull
+ @Override
+ public MappingContext getMappingContext() {
+ return mappingContext;
+ }
+
+ @Override
+ public void close() {
+ // Make sure to clear the storage in case some customizer stored a reference to it to prevent memory leaks
+ ctx.close();
+ }
+ }
+}
diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/WriteTransaction.java b/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/WriteTransaction.java
new file mode 100644
index 0000000..c8f9bd3
--- /dev/null
+++ b/infra/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/WriteTransaction.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.data.impl;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.CANCELED;
+import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.COMMITED;
+import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.FAILED;
+import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.NEW;
+import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.SUBMITED;
+
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import io.fd.honeycomb.v3po.data.DataModification;
+import io.fd.honeycomb.v3po.translate.TranslationException;
+import java.util.function.Consumer;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.NotThreadSafe;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@NotThreadSafe
+final class WriteTransaction implements DOMDataWriteTransaction {
+
+ private static final Logger LOG = LoggerFactory.getLogger(WriteTransaction.class);
+
+ @Nullable
+ private DataModification operationalModification;
+ @Nullable
+ private DataModification configModification;
+ private TransactionStatus status = NEW;
+
+ private WriteTransaction(@Nullable final DataModification configModification,
+ @Nullable final DataModification operationalModification) {
+ this.operationalModification = operationalModification;
+ this.configModification = configModification;
+ }
+
+ private void checkIsNew() {
+ Preconditions.checkState(status == NEW, "Transaction was submitted or canceled");
+ }
+
+ @Override
+ public void put(final LogicalDatastoreType store, final YangInstanceIdentifier path,
+ final NormalizedNode<?, ?> data) {
+ LOG.debug("WriteTransaction.put() store={}, path={}, data={}", store, path, data);
+ checkIsNew();
+ handleOperation(store, (modification) -> modification.write(path, data));
+ }
+
+ private void handleOperation(final LogicalDatastoreType store,
+ final Consumer<DataModification> r) {
+ switch (store) {
+ case CONFIGURATION:
+ checkArgument(configModification != null, "Modification of %s is not supported", store);
+ r.accept(configModification);
+ break;
+ case OPERATIONAL:
+ checkArgument(operationalModification != null, "Modification of %s is not supported", store);
+ r.accept(operationalModification);
+ break;
+ }
+ }
+
+ @Override
+ public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path,
+ final NormalizedNode<?, ?> data) {
+ LOG.debug("WriteTransaction.merge() store={}, path={}, data={}", store, path, data);
+ checkIsNew();
+ handleOperation(store, (modification) -> modification.merge(path, data));
+ }
+
+ @Override
+ public boolean cancel() {
+ if (status != NEW) {
+ // only NEW transactions can be cancelled
+ return false;
+ } else {
+ status = CANCELED;
+ return true;
+ }
+ }
+
+ @Override
+ public void delete(LogicalDatastoreType store, final YangInstanceIdentifier path) {
+ LOG.debug("WriteTransaction.delete() store={}, path={}", store, path);
+ checkIsNew();
+ handleOperation(store, (modification) -> modification.delete(path));
+ }
+
+ @Override
+ public CheckedFuture<Void, TransactionCommitFailedException> submit() {
+ LOG.trace("WriteTransaction.submit()");
+ checkIsNew();
+
+ try {
+ status = SUBMITED;
+
+ // Validate first to catch any issues before attempting commit
+ if (configModification != null) {
+ configModification.validate();
+ }
+ if (operationalModification != null) {
+ operationalModification.validate();
+ }
+
+ if(configModification != null) {
+ configModification.commit();
+ }
+ if(operationalModification != null) {
+ operationalModification.commit();
+ }
+
+ status = COMMITED;
+ } catch (DataValidationFailedException | TranslationException e) {
+ status = FAILED;
+ LOG.error("Failed modify data tree", e);
+ return Futures.immediateFailedCheckedFuture(
+ new TransactionCommitFailedException("Failed to validate DataTreeModification", e));
+ }
+ return Futures.immediateCheckedFuture(null);
+ }
+
+ @Override
+ @Deprecated
+ public ListenableFuture<RpcResult<TransactionStatus>> commit() {
+ throw new UnsupportedOperationException("deprecated");
+ }
+
+ @Override
+ public Object getIdentifier() {
+ return this;
+ }
+
+
+ @Nonnull
+ static WriteTransaction createOperationalOnly(@Nonnull final DataModification operationalData) {
+ return new WriteTransaction(null, requireNonNull(operationalData));
+ }
+
+ @Nonnull
+ static WriteTransaction createConfigOnly(@Nonnull final DataModification configData) {
+ return new WriteTransaction(requireNonNull(configData), null);
+ }
+
+ @Nonnull
+ static WriteTransaction create(@Nonnull final DataModification configData,
+ @Nonnull final DataModification operationalData) {
+ return new WriteTransaction(requireNonNull(configData), requireNonNull(operationalData));
+ }
+}
diff --git a/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/ConfigDataTreeModule.java b/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/ConfigDataTreeModule.java
new file mode 100644
index 0000000..eabcdcb
--- /dev/null
+++ b/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/ConfigDataTreeModule.java
@@ -0,0 +1,71 @@
+package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.impl.rev160411;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import io.fd.honeycomb.v3po.data.DataModification;
+import io.fd.honeycomb.v3po.data.ModifiableDataManager;
+import io.fd.honeycomb.v3po.data.impl.ModifiableDataTreeDelegator;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ConfigDataTreeModule extends
+ org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.impl.rev160411.AbstractConfigDataTreeModule {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ConfigDataTreeModule.class);
+
+ public ConfigDataTreeModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier,
+ org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public ConfigDataTreeModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier,
+ org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+ org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.impl.rev160411.ConfigDataTreeModule oldModule,
+ java.lang.AutoCloseable oldInstance) {
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ public void customValidation() {
+ // add custom validation form module attributes here.
+ }
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+ LOG.debug("ConfigDataTreeModule.createInstance()");
+ return new CloseableConfigDataTree(
+ new ModifiableDataTreeDelegator(getSerializerDependency(), getDataTreeDependency(),
+ getWriterRegistryBuilderDependency().build(), getContextBindingBrokerDependency()));
+ }
+
+ private static final class CloseableConfigDataTree implements ModifiableDataManager, AutoCloseable {
+
+ private final ModifiableDataTreeDelegator delegate;
+
+ CloseableConfigDataTree(final ModifiableDataTreeDelegator delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void close() throws Exception {
+ LOG.debug("CloseableConfigDataTree.close()");
+ // NOP
+ }
+
+ @Override
+ public DataModification newModification() {
+ LOG.trace("CloseableConfigDataTree.newModification");
+ return delegate.newModification();
+ }
+
+ @Override
+ public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(
+ @Nonnull final YangInstanceIdentifier path) {
+ return delegate.read(path);
+ }
+ }
+}
diff --git a/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/ConfigDataTreeModuleFactory.java b/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/ConfigDataTreeModuleFactory.java
new file mode 100644
index 0000000..19baab1
--- /dev/null
+++ b/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/ConfigDataTreeModuleFactory.java
@@ -0,0 +1,13 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: data-impl yang module local name: config-data-tree
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Sun Apr 10 22:07:29 CEST 2016
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.impl.rev160411;
+public class ConfigDataTreeModuleFactory extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.impl.rev160411.AbstractConfigDataTreeModuleFactory {
+
+}
diff --git a/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/InMemoryDataTreeModule.java b/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/InMemoryDataTreeModule.java
new file mode 100644
index 0000000..99e5b39
--- /dev/null
+++ b/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/InMemoryDataTreeModule.java
@@ -0,0 +1,79 @@
+package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.impl.rev160411;
+
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.api.rev160411.DatatreeType;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.*;
+import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class InMemoryDataTreeModule extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.impl.rev160411.AbstractInMemoryDataTreeModule {
+
+ private static final Logger LOG = LoggerFactory.getLogger(InMemoryDataTreeModule.class);
+
+ public InMemoryDataTreeModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public InMemoryDataTreeModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.impl.rev160411.InMemoryDataTreeModule oldModule, java.lang.AutoCloseable oldInstance) {
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ public void customValidation() {
+ // add custom validation form module attributes here.
+ }
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+ LOG.debug("InMemoryConfigDataTreeModule.createInstance()");
+ return new CloseableConfigDataTree(getSchemaServiceDependency().getGlobalContext(), getType());
+ }
+
+ private static class CloseableConfigDataTree implements AutoCloseable, DataTree {
+ private final DataTree dataTree;
+
+ CloseableConfigDataTree(final SchemaContext schemaContext, final DatatreeType type) {
+ this.dataTree = InMemoryDataTreeFactory.getInstance().create(
+ type == DatatreeType.Config ? TreeType.CONFIGURATION : TreeType.OPERATIONAL
+ );
+ dataTree.setSchemaContext(schemaContext);
+ }
+
+ @Override
+ public void close() throws Exception {
+ // NOP
+ }
+
+ @Override
+ public DataTreeSnapshot takeSnapshot() {
+ return dataTree.takeSnapshot();
+ }
+
+ @Override
+ public void setSchemaContext(final SchemaContext newSchemaContext) {
+ dataTree.setSchemaContext(newSchemaContext);
+ }
+
+ @Override
+ public void commit(final DataTreeCandidate candidate) {
+ dataTree.commit(candidate);
+ }
+
+ @Override
+ public YangInstanceIdentifier getRootPath() {
+ return dataTree.getRootPath();
+ }
+
+ @Override
+ public void validate(final DataTreeModification modification) throws DataValidationFailedException {
+ dataTree.validate(modification);
+ }
+
+ @Override
+ public DataTreeCandidate prepare(final DataTreeModification modification) {
+ return dataTree.prepare(modification);
+ }
+ }
+}
diff --git a/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/InMemoryDataTreeModuleFactory.java b/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/InMemoryDataTreeModuleFactory.java
new file mode 100644
index 0000000..34a5439
--- /dev/null
+++ b/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/InMemoryDataTreeModuleFactory.java
@@ -0,0 +1,13 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: data-impl yang module local name: inmemory-data-tree
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Fri May 13 11:10:56 CEST 2016
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.impl.rev160411;
+public class InMemoryDataTreeModuleFactory extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.impl.rev160411.AbstractInMemoryDataTreeModuleFactory {
+
+}
diff --git a/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/OperationalDataTreeModule.java b/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/OperationalDataTreeModule.java
new file mode 100644
index 0000000..1526fdd
--- /dev/null
+++ b/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/OperationalDataTreeModule.java
@@ -0,0 +1,65 @@
+package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.impl.rev160411;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import io.fd.honeycomb.v3po.data.ReadableDataManager;
+import io.fd.honeycomb.v3po.data.impl.ReadableDataTreeDelegator;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class OperationalDataTreeModule extends
+ org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.impl.rev160411.AbstractOperationalDataTreeModule {
+
+ private static final Logger LOG = LoggerFactory.getLogger(OperationalDataTreeModule.class);
+
+ public OperationalDataTreeModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier,
+ org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public OperationalDataTreeModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier,
+ org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+ org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.impl.rev160411.OperationalDataTreeModule oldModule,
+ java.lang.AutoCloseable oldInstance) {
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ public void customValidation() {
+ // add custom validation form module attributes here.
+ }
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+ LOG.debug("OperationalDataTreeModule.createInstance()");
+ return new CloseableOperationalDataTree(
+ new ReadableDataTreeDelegator(getSerializerDependency(), getSchemaServiceDependency().getGlobalContext(),
+ getReaderRegistryBuilderDependency().build(), getContextBindingBrokerDependency()));
+ }
+
+ private static final class CloseableOperationalDataTree implements ReadableDataManager, AutoCloseable {
+
+ private final ReadableDataTreeDelegator delegate;
+
+ CloseableOperationalDataTree(final ReadableDataTreeDelegator delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void close() throws Exception {
+ LOG.debug("CloseableOperationalDataTree.close()");
+ // NOP
+ }
+
+ @Override
+ public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(
+ @Nonnull final YangInstanceIdentifier path) {
+ LOG.trace("CloseableOperationalDataTree.read path={}", path);
+ return delegate.read(path);
+ }
+ }
+}
diff --git a/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/OperationalDataTreeModuleFactory.java b/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/OperationalDataTreeModuleFactory.java
new file mode 100644
index 0000000..221eabe
--- /dev/null
+++ b/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/OperationalDataTreeModuleFactory.java
@@ -0,0 +1,13 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: data-impl yang module local name: honeycomb-operational-data-tree
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Sun Apr 10 23:52:21 CEST 2016
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.impl.rev160411;
+public class OperationalDataTreeModuleFactory extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.impl.rev160411.AbstractOperationalDataTreeModuleFactory {
+
+}
diff --git a/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/PersistingDataTreeAdapterModule.java b/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/PersistingDataTreeAdapterModule.java
new file mode 100644
index 0000000..145fc43
--- /dev/null
+++ b/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/PersistingDataTreeAdapterModule.java
@@ -0,0 +1,38 @@
+package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.impl.rev160411;
+
+import java.nio.file.InvalidPathException;
+import java.nio.file.Paths;
+import org.opendaylight.controller.config.api.JmxAttributeValidationException;
+
+public class PersistingDataTreeAdapterModule extends
+ org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.impl.rev160411.AbstractPersistingDataTreeAdapterModule {
+ public PersistingDataTreeAdapterModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier,
+ org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public PersistingDataTreeAdapterModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier,
+ org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+ org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.impl.rev160411.PersistingDataTreeAdapterModule oldModule,
+ java.lang.AutoCloseable oldInstance) {
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ public void customValidation() {
+ try {
+ Paths.get(getPersistFilePath());
+ } catch (InvalidPathException e) {
+ throw new JmxAttributeValidationException("Invalid persist path", e, persistFilePathJmxAttribute);
+ }
+ }
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+ return new io.fd.honeycomb.v3po.data.impl.PersistingDataTreeAdapter(
+ getDelegateDependency(),
+ getSchemaServiceDependency(),
+ Paths.get(getPersistFilePath()));
+ }
+
+}
diff --git a/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/PersistingDataTreeAdapterModuleFactory.java b/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/PersistingDataTreeAdapterModuleFactory.java
new file mode 100644
index 0000000..0b7546c
--- /dev/null
+++ b/infra/data-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/data/impl/rev160411/PersistingDataTreeAdapterModuleFactory.java
@@ -0,0 +1,13 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: data-impl yang module local name: persisting-data-tree-adapter
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Thu May 12 14:07:24 CEST 2016
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.impl.rev160411;
+public class PersistingDataTreeAdapterModuleFactory extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.data.impl.rev160411.AbstractPersistingDataTreeAdapterModuleFactory {
+
+}
diff --git a/infra/data-impl/src/main/yang/data-impl.yang b/infra/data-impl/src/main/yang/data-impl.yang
new file mode 100644
index 0000000..ee48553
--- /dev/null
+++ b/infra/data-impl/src/main/yang/data-impl.yang
@@ -0,0 +1,179 @@
+module data-impl {
+ yang-version 1;
+ namespace "urn:honeycomb:params:xml:ns:yang:data:impl";
+ prefix "tutils";
+
+ import config { prefix config; revision-date 2013-04-05; }
+ import opendaylight-md-sal-binding { prefix md-sal-binding; revision-date 2013-10-28;}
+ import opendaylight-md-sal-dom { prefix dom; revision-date 2013-10-28;}
+ import data-api { prefix dapi; revision-date 2016-04-11; }
+ import translate-api { prefix tapi; revision-date 2016-04-06; }
+
+ description
+ "This module contains YANG module definitions
+ for honeycomd data layer";
+
+ revision "2016-04-11" {
+ description
+ "Initial revision.";
+ }
+
+ identity inmemory-data-tree {
+ base config:module-type;
+ config:provided-service dapi:data-tree;
+ config:java-name-prefix InMemoryDataTree;
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case inmemory-data-tree {
+ when "/config:modules/config:module/config:type = 'inmemory-data-tree'";
+
+ container schema-service {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity dom:schema-service;
+ }
+ }
+ }
+
+ leaf type {
+ type dapi:datatree-type;
+ mandatory true;
+ }
+ }
+ }
+
+ identity persisting-data-tree-adapter {
+ base config:module-type;
+ config:provided-service dapi:data-tree;
+ config:java-name-prefix PersistingDataTreeAdapter;
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case persisting-data-tree-adapter {
+ when "/config:modules/config:module/config:type = 'persisting-data-tree-adapter'";
+
+ container delegate {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity dapi:data-tree;
+ }
+ }
+ }
+
+ container schema-service {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity dom:schema-service;
+ }
+ }
+ }
+
+ leaf persist-file-path {
+ type string;
+ mandatory true;
+ description "Path to a file to be used as data storage";
+ }
+ }
+ }
+
+ identity honeycomb-config-data-tree {
+ base config:module-type;
+ config:provided-service dapi:honeycomb-modifiable-data-tree;
+ config:java-name-prefix ConfigDataTree;
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case honeycomb-config-data-tree {
+ when "/config:modules/config:module/config:type = 'honeycomb-config-data-tree'";
+
+ container data-tree {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity dapi:data-tree;
+ }
+ }
+ }
+
+ container serializer {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity md-sal-binding:binding-normalized-node-serializer;
+ }
+ }
+ }
+
+ container writer-registry-builder {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity tapi:honeycomb-writer-registry-builder;
+ }
+ }
+ }
+
+ container context-binding-broker {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity md-sal-binding:binding-async-data-broker;
+ }
+ }
+ }
+ }
+ }
+
+ identity honeycomb-operational-data-tree {
+ base config:module-type;
+ config:provided-service dapi:honeycomb-readable-data-tree;
+ config:java-name-prefix OperationalDataTree;
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case honeycomb-operational-data-tree {
+ when "/config:modules/config:module/config:type = 'honeycomb-operational-data-tree'";
+
+ container schema-service {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity dom:schema-service;
+ }
+ }
+ }
+
+ container serializer {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity md-sal-binding:binding-normalized-node-serializer;
+ }
+ }
+ }
+
+ container reader-registry-builder {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity tapi:honeycomb-reader-registry-builder;
+ }
+ }
+ }
+
+ container context-binding-broker {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity md-sal-binding:binding-async-data-broker;
+ }
+ }
+ }
+
+ }
+ }
+} \ No newline at end of file
diff --git a/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/DataBrokerTest.java b/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/DataBrokerTest.java
new file mode 100644
index 0000000..55b92b5
--- /dev/null
+++ b/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/DataBrokerTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.data.impl;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import io.fd.honeycomb.v3po.data.ReadableDataManager;
+import io.fd.honeycomb.v3po.data.ModifiableDataManager;
+import io.fd.honeycomb.v3po.data.DataModification;
+import java.util.Map;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+
+public class DataBrokerTest {
+
+ @Mock
+ private ReadableDataManager operationalData;
+ @Mock
+ private ModifiableDataManager confiDataTree;
+ @Mock
+ private DataModification configSnapshot;
+ private DataBroker broker;
+
+ @Before
+ public void setUp() {
+ initMocks(this);
+ when(confiDataTree.newModification()).thenReturn(configSnapshot);
+ broker = DataBroker.create(confiDataTree, operationalData);
+ }
+
+ @Test
+ public void testNewReadWriteTransaction() {
+ final DOMDataReadWriteTransaction readWriteTx = broker.newReadWriteTransaction();
+ final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class);
+ readWriteTx.read(LogicalDatastoreType.CONFIGURATION, path);
+
+ // verify that read and write transactions use the same config snapshot
+ verify(configSnapshot).read(path);
+ verify(confiDataTree).newModification();
+ }
+
+ @Test
+ public void testNewWriteOnlyTransaction() {
+ final DOMDataWriteTransaction writeTx = broker.newWriteOnlyTransaction();
+
+ // verify that write transactions use config snapshot
+ verify(confiDataTree).newModification();
+ }
+
+ @Test
+ public void testNewReadOnlyTransaction() {
+ final DOMDataReadOnlyTransaction readTx = broker.newReadOnlyTransaction();
+
+ final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class);
+ readTx.read(LogicalDatastoreType.CONFIGURATION, path);
+
+ // verify that read transactions use config snapshot
+ verify(configSnapshot).read(path);
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testRegisterDataChangeListener() {
+ final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class);
+ final DOMDataChangeListener listener = mock(DOMDataChangeListener.class);
+ broker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, path, listener,
+ AsyncDataBroker.DataChangeScope.BASE);
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testCreateTransactionChain() {
+ final TransactionChainListener listener = mock(TransactionChainListener.class);
+ broker.createTransactionChain(listener);
+ }
+
+ @Test
+ public void testGetSupportedExtensions() {
+ final Map<Class<? extends DOMDataBrokerExtension>, DOMDataBrokerExtension> supportedExtensions =
+ broker.getSupportedExtensions();
+ assertTrue(supportedExtensions.isEmpty());
+ }
+
+
+} \ No newline at end of file
diff --git a/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegatorTest.java b/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegatorTest.java
new file mode 100644
index 0000000..915d738
--- /dev/null
+++ b/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegatorTest.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.data.impl;
+
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.hamcrest.CoreMatchers.hasItems;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.Multimap;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import io.fd.honeycomb.v3po.data.DataModification;
+import io.fd.honeycomb.v3po.translate.TranslationException;
+import io.fd.honeycomb.v3po.translate.write.DataObjectUpdate;
+import io.fd.honeycomb.v3po.translate.write.WriteContext;
+import io.fd.honeycomb.v3po.translate.write.registry.WriterRegistry;
+import java.util.AbstractMap;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
+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.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
+
+public class ModifiableDataTreeDelegatorTest {
+
+ @Mock
+ private WriterRegistry writer;
+ @Mock
+ private BindingNormalizedNodeSerializer serializer;
+ private DataTree dataTree;
+ @Mock
+ private org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification modification;
+ @Mock
+ private DataBroker contextBroker;
+ @Mock
+ private org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction tx;
+
+ private ModifiableDataTreeManager configDataTree;
+
+ static final InstanceIdentifier<?> DEFAULT_ID = InstanceIdentifier.create(DataObject.class);
+ static DataObject DEFAULT_DATA_OBJECT = mockDataObject("serialized", DataObject.class);
+
+ @Before
+ public void setUp() throws Exception {
+ initMocks(this);
+ dataTree = ModificationDiffTest.getDataTree();
+ when(contextBroker.newReadWriteTransaction()).thenReturn(tx);
+ when(tx.submit()).thenReturn(Futures.immediateCheckedFuture(null));
+
+ when(serializer.fromYangInstanceIdentifier(any(YangInstanceIdentifier.class))).thenReturn(((InstanceIdentifier) DEFAULT_ID));
+ final Map.Entry<InstanceIdentifier<?>, DataObject> parsed = new AbstractMap.SimpleEntry<>(DEFAULT_ID, DEFAULT_DATA_OBJECT);
+ when(serializer.fromNormalizedNode(any(YangInstanceIdentifier.class), any(NormalizedNode.class))).thenReturn(parsed);
+
+ configDataTree = new ModifiableDataTreeDelegator(serializer, dataTree, writer, contextBroker);
+ }
+
+ @Test
+ public void testRead() throws Exception {
+ final ContainerNode topContainer = ModificationDiffTest.getTopContainer("topContainer");
+ ModificationDiffTest.addNodeToTree(dataTree, topContainer, ModificationDiffTest.TOP_CONTAINER_ID);
+ final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read =
+ configDataTree.read(ModificationDiffTest.TOP_CONTAINER_ID);
+ final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read2 =
+ configDataTree.newModification().read(ModificationDiffTest.TOP_CONTAINER_ID);
+ final Optional<NormalizedNode<?, ?>> normalizedNodeOptional = read.get();
+ final Optional<NormalizedNode<?, ?>> normalizedNodeOptional2 = read2.get();
+
+ assertEquals(normalizedNodeOptional, normalizedNodeOptional2);
+ assertTrue(normalizedNodeOptional.isPresent());
+ assertEquals(topContainer, normalizedNodeOptional.get());
+ assertEquals(dataTree.takeSnapshot().readNode(ModificationDiffTest.TOP_CONTAINER_ID), normalizedNodeOptional);
+ }
+
+ @Test
+ public void testCommitSuccessful() throws Exception {
+ final MapNode nestedList = ModificationDiffTest.getNestedList("listEntry", "listValue");
+
+ final DataModification dataModification = configDataTree.newModification();
+ dataModification.write(ModificationDiffTest.NESTED_LIST_ID, nestedList);
+ dataModification.validate();
+ dataModification.commit();
+
+ final Multimap<InstanceIdentifier<?>, DataObjectUpdate> map = HashMultimap.create();
+ map.put(DEFAULT_ID, DataObjectUpdate.create(DEFAULT_ID, DEFAULT_DATA_OBJECT, DEFAULT_DATA_OBJECT));
+ verify(writer).update(eq(new WriterRegistry.DataObjectUpdates(map, ImmutableMultimap.of())), any(WriteContext.class));
+ assertEquals(nestedList, dataTree.takeSnapshot().readNode(ModificationDiffTest.NESTED_LIST_ID).get());
+ }
+
+ private static DataObject mockDataObject(final String name, final Class<? extends DataObject> classToMock) {
+ final DataObject dataBefore = mock(classToMock, name);
+ doReturn(classToMock).when(dataBefore).getImplementedInterface();
+ return dataBefore;
+ }
+
+ @Test
+ public void testCommitUndoSuccessful() throws Exception {
+ final MapNode nestedList = ModificationDiffTest.getNestedList("listEntry", "listValue");
+
+ // Fail on update:
+ final WriterRegistry.Reverter reverter = mock(WriterRegistry.Reverter.class);
+ final TranslationException failedOnUpdateException = new TranslationException("update failed");
+ doThrow(new WriterRegistry.BulkUpdateException(Collections.singleton(DEFAULT_ID), reverter, failedOnUpdateException))
+ .when(writer).update(any(WriterRegistry.DataObjectUpdates.class), any(WriteContext.class));
+
+ try {
+ // Run the test
+ final DataModification dataModification = configDataTree.newModification();
+ dataModification.write(ModificationDiffTest.NESTED_LIST_ID, nestedList);
+ dataModification.validate();
+ dataModification.commit();
+ fail("WriterRegistry.BulkUpdateException was expected");
+ } catch (WriterRegistry.BulkUpdateException e) {
+ verify(writer).update(any(WriterRegistry.DataObjectUpdates.class), any(WriteContext.class));
+ assertThat(e.getFailedIds(), hasItem(DEFAULT_ID));
+ verify(reverter).revert();
+ assertEquals(failedOnUpdateException, e.getCause());
+ }
+ }
+
+ @Test
+ public void testCommitUndoFailed() throws Exception {
+ final MapNode nestedList = ModificationDiffTest.getNestedList("listEntry", "listValue");
+
+ // Fail on update:
+ final WriterRegistry.Reverter reverter = mock(WriterRegistry.Reverter.class);
+ final TranslationException failedOnUpdateException = new TranslationException("update failed");
+ doThrow(new WriterRegistry.BulkUpdateException(Collections.singleton(DEFAULT_ID), reverter, failedOnUpdateException))
+ .when(writer).update(any(WriterRegistry.DataObjectUpdates.class), any(WriteContext.class));
+
+ // Fail on revert:
+ final TranslationException failedOnRevertException = new TranslationException("revert failed");
+ doThrow(new WriterRegistry.Reverter.RevertFailedException(Collections.emptySet(), failedOnRevertException))
+ .when(reverter).revert();
+
+ try {
+ // Run the test
+ final DataModification dataModification = configDataTree.newModification();
+ dataModification.write(ModificationDiffTest.NESTED_LIST_ID, nestedList);
+ dataModification.validate();
+ dataModification.commit();
+ fail("WriterRegistry.Reverter.RevertFailedException was expected");
+ } catch (WriterRegistry.Reverter.RevertFailedException e) {
+ verify(writer).update(any(WriterRegistry.DataObjectUpdates.class), any(WriteContext.class));
+ verify(reverter).revert();
+ assertEquals(failedOnRevertException, e.getCause());
+ }
+ }
+
+ private abstract static class DataObject1 implements DataObject {}
+ private abstract static class DataObject2 implements DataObject {}
+ private abstract static class DataObject3 implements DataObject {}
+
+ @Test
+ public void testToBindingAware() throws Exception {
+ when(serializer.fromNormalizedNode(any(YangInstanceIdentifier.class), eq(null))).thenReturn(null);
+
+ final Map<YangInstanceIdentifier, ModificationDiff.NormalizedNodeUpdate> biNodes = new HashMap<>();
+ // delete
+ final QName nn1 = QName.create("namespace", "nn1");
+ final YangInstanceIdentifier yid1 = mockYid(nn1);
+ final InstanceIdentifier iid1 = mockIid(yid1, DataObject1.class);
+ final NormalizedNode nn1B = mockNormalizedNode(nn1);
+ final DataObject1 do1B = mockDataObject(yid1, iid1, nn1B, DataObject1.class);
+ biNodes.put(yid1, ModificationDiff.NormalizedNodeUpdate.create(yid1, nn1B, null));
+
+ // create
+ final QName nn2 = QName.create("namespace", "nn1");
+ final YangInstanceIdentifier yid2 = mockYid(nn2);
+ final InstanceIdentifier iid2 = mockIid(yid2, DataObject2.class);;
+ final NormalizedNode nn2A = mockNormalizedNode(nn2);
+ final DataObject2 do2A = mockDataObject(yid2, iid2, nn2A, DataObject2.class);
+ biNodes.put(yid2, ModificationDiff.NormalizedNodeUpdate.create(yid2, null, nn2A));
+
+ // update
+ final QName nn3 = QName.create("namespace", "nn1");
+ final YangInstanceIdentifier yid3 = mockYid(nn3);
+ final InstanceIdentifier iid3 = mockIid(yid3, DataObject3.class);
+ final NormalizedNode nn3B = mockNormalizedNode(nn3);
+ final DataObject3 do3B = mockDataObject(yid3, iid3, nn3B, DataObject3.class);
+ final NormalizedNode nn3A = mockNormalizedNode(nn3);
+ final DataObject3 do3A = mockDataObject(yid3, iid3, nn3A, DataObject3.class);;
+ biNodes.put(yid3, ModificationDiff.NormalizedNodeUpdate.create(yid3, nn3B, nn3A));
+
+ final WriterRegistry.DataObjectUpdates dataObjectUpdates =
+ ModifiableDataTreeDelegator.toBindingAware(biNodes, serializer);
+
+ assertThat(dataObjectUpdates.getDeletes().size(), is(1));
+ assertThat(dataObjectUpdates.getDeletes().keySet(), hasItem(((InstanceIdentifier<?>) iid1)));
+ assertThat(dataObjectUpdates.getDeletes().values(), hasItem(
+ ((DataObjectUpdate.DataObjectDelete) DataObjectUpdate.create(iid1, do1B, null))));
+
+ assertThat(dataObjectUpdates.getUpdates().size(), is(2));
+ assertThat(dataObjectUpdates.getUpdates().keySet(), hasItems((InstanceIdentifier<?>) iid2, (InstanceIdentifier<?>) iid3));
+ assertThat(dataObjectUpdates.getUpdates().values(), hasItems(
+ DataObjectUpdate.create(iid2, null, do2A),
+ DataObjectUpdate.create(iid3, do3B, do3A)));
+
+ assertThat(dataObjectUpdates.getTypeIntersection().size(), is(3));
+ }
+
+ private <D extends DataObject> D mockDataObject(final YangInstanceIdentifier yid1,
+ final InstanceIdentifier iid1,
+ final NormalizedNode nn1B,
+ final Class<D> type) {
+ final D do1B = mock(type);
+ when(serializer.fromNormalizedNode(yid1, nn1B)).thenReturn(new AbstractMap.SimpleEntry<>(iid1, do1B));
+ return do1B;
+ }
+
+ private NormalizedNode mockNormalizedNode(final QName nn1) {
+ final NormalizedNode nn1B = mock(NormalizedNode.class);
+ when(nn1B.getNodeType()).thenReturn(nn1);
+ return nn1B;
+ }
+
+ private InstanceIdentifier mockIid(final YangInstanceIdentifier yid1,
+ final Class<? extends DataObject> type) {
+ final InstanceIdentifier iid1 = InstanceIdentifier.create(type);
+ when(serializer.fromYangInstanceIdentifier(yid1)).thenReturn(iid1);
+ return iid1;
+ }
+
+ private YangInstanceIdentifier mockYid(final QName nn1) {
+ final YangInstanceIdentifier yid1 = mock(YangInstanceIdentifier.class);
+ when(yid1.getLastPathArgument()).thenReturn(new YangInstanceIdentifier.NodeIdentifier(nn1));
+ return yid1;
+ }
+}
diff --git a/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ModificationDiffTest.java b/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ModificationDiffTest.java
new file mode 100644
index 0000000..bc7582e
--- /dev/null
+++ b/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ModificationDiffTest.java
@@ -0,0 +1,427 @@
+package io.fd.honeycomb.v3po.data.impl;
+
+import static org.hamcrest.CoreMatchers.hasItems;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+import java.util.Map;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateTip;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.TipProducingDataTree;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangInferencePipeline;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangStatementSourceImpl;
+
+public class ModificationDiffTest {
+
+ static final QName TOP_CONTAINER_QNAME =
+ QName.create("urn:opendaylight:params:xml:ns:yang:test:diff", "2015-01-05", "top-container");
+ static final QName STRING_LEAF_QNAME = QName.create(TOP_CONTAINER_QNAME, "string");
+ static final QName NAME_LEAF_QNAME = QName.create(TOP_CONTAINER_QNAME, "name");
+ static final QName TEXT_LEAF_QNAME = QName.create(TOP_CONTAINER_QNAME, "text");
+ static final QName NESTED_LIST_QNAME = QName.create(TOP_CONTAINER_QNAME, "nested-list");
+ static final QName DEEP_LIST_QNAME = QName.create(TOP_CONTAINER_QNAME, "deep-list");
+
+ static final QName WITH_CHOICE_CONTAINER_QNAME =
+ QName.create("urn:opendaylight:params:xml:ns:yang:test:diff", "2015-01-05", "with-choice");
+ static final QName CHOICE_QNAME = QName.create(WITH_CHOICE_CONTAINER_QNAME, "choice");
+ static final QName IN_CASE1_LEAF_QNAME = QName.create(WITH_CHOICE_CONTAINER_QNAME, "in-case1");
+ static final QName IN_CASE2_LEAF_QNAME = QName.create(WITH_CHOICE_CONTAINER_QNAME, "in-case2");
+
+ static final YangInstanceIdentifier TOP_CONTAINER_ID = YangInstanceIdentifier.of(TOP_CONTAINER_QNAME);
+ static final YangInstanceIdentifier NESTED_LIST_ID = TOP_CONTAINER_ID.node(new YangInstanceIdentifier.NodeIdentifier(NESTED_LIST_QNAME));
+
+
+ @Test
+ public void testInitialWrite() throws Exception {
+ final TipProducingDataTree dataTree = getDataTree();
+ final DataTreeModification dataTreeModification = getModification(dataTree);
+ final NormalizedNode<?, ?> topContainer = getTopContainer("string1");
+ final YangInstanceIdentifier TOP_CONTAINER_ID = YangInstanceIdentifier.of(TOP_CONTAINER_QNAME);
+ dataTreeModification.write(TOP_CONTAINER_ID, topContainer);
+ final DataTreeCandidateTip prepare = prepareModification(dataTree, dataTreeModification);
+
+ final ModificationDiff modificationDiff = getModificationDiff(prepare);
+
+ assertThat(modificationDiff.getUpdates().size(), is(1));
+ assertThat(modificationDiff.getUpdates().values().size(), is(1));
+ assertUpdate(modificationDiff.getUpdates().values().iterator().next(), TOP_CONTAINER_ID, null, topContainer);
+ }
+
+ @Test
+ public void testInitialWriteForContainerWithChoice() throws Exception {
+ final TipProducingDataTree dataTree = getDataTree();
+ final DataTreeModification dataTreeModification = getModification(dataTree);
+ final ContainerNode containerWithChoice = Builders.containerBuilder()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(WITH_CHOICE_CONTAINER_QNAME))
+ .withChild(Builders.choiceBuilder()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(CHOICE_QNAME))
+ .withChild(ImmutableNodes.leafNode(IN_CASE1_LEAF_QNAME, "withinCase1"))
+ .build())
+ .build();
+ final YangInstanceIdentifier WITH_CHOICE_CONTAINER_ID = YangInstanceIdentifier.of(WITH_CHOICE_CONTAINER_QNAME);
+ dataTreeModification.write(WITH_CHOICE_CONTAINER_ID, containerWithChoice);
+ final DataTreeCandidateTip prepare = prepareModification(dataTree, dataTreeModification);
+
+ final Map<YangInstanceIdentifier, ModificationDiff.NormalizedNodeUpdate> updates = getModificationDiff(prepare).getUpdates();
+
+ assertThat(updates.size(), is(1));
+ assertUpdate(getNormalizedNodeUpdateForAfterType(updates, ContainerNode.class),
+ WITH_CHOICE_CONTAINER_ID, null, containerWithChoice);
+ }
+
+ private DataTreeModification getModification(final TipProducingDataTree dataTree) {
+ final DataTreeSnapshot dataTreeSnapshot = dataTree.takeSnapshot();
+ return dataTreeSnapshot.newModification();
+ }
+
+ @Test
+ public void testWriteNonPresenceEmptyContainer() throws Exception {
+ final TipProducingDataTree dataTree = getDataTree();
+ final DataTreeModification dataTreeModification = getModification(dataTree);
+ final NormalizedNode<?, ?> topContainer = ImmutableNodes.containerNode(TOP_CONTAINER_QNAME);
+ dataTreeModification.write(TOP_CONTAINER_ID, topContainer);
+ final DataTreeCandidateTip prepare = prepareModification(dataTree, dataTreeModification);
+
+ final ModificationDiff modificationDiff = getModificationDiff(prepare);
+
+ assertThat(modificationDiff.getUpdates().size(), is(0));
+ }
+
+ private DataTreeCandidateTip prepareModification(final TipProducingDataTree dataTree,
+ final DataTreeModification dataTreeModification)
+ throws DataValidationFailedException {
+ dataTreeModification.ready();
+ dataTree.validate(dataTreeModification);
+ return dataTree.prepare(dataTreeModification);
+ }
+
+ @Test
+ public void testUpdateWrite() throws Exception {
+ final TipProducingDataTree dataTree = getDataTree();
+ final ContainerNode topContainer = getTopContainer("string1");
+ addNodeToTree(dataTree, topContainer, TOP_CONTAINER_ID);
+
+ final DataTreeModification dataTreeModification = getModification(dataTree);
+ final NormalizedNode<?, ?> topContainerAfter = getTopContainer("string2");
+ dataTreeModification.write(TOP_CONTAINER_ID, topContainerAfter);
+ final DataTreeCandidateTip prepare = prepareModification(dataTree, dataTreeModification);
+
+ final Map<YangInstanceIdentifier, ModificationDiff.NormalizedNodeUpdate> updates = getModificationDiff(prepare).getUpdates();
+
+ assertThat(updates.size(), is(1));
+ assertThat(updates.values().size(), is(1));
+ assertUpdate(updates.values().iterator().next(), TOP_CONTAINER_ID, topContainer, topContainerAfter);
+ }
+
+ private ModificationDiff getModificationDiff(final DataTreeCandidateTip prepare) {
+ return ModificationDiff.recursivelyFromCandidate(YangInstanceIdentifier.EMPTY, prepare.getRootNode());
+ }
+
+ @Test
+ public void testUpdateMerge() throws Exception {
+ final TipProducingDataTree dataTree = getDataTree();
+ final ContainerNode topContainer = getTopContainer("string1");
+ addNodeToTree(dataTree, topContainer, TOP_CONTAINER_ID);
+
+ final DataTreeModification dataTreeModification = getModification(dataTree);
+ final NormalizedNode<?, ?> topContainerAfter = getTopContainer("string2");
+ dataTreeModification.merge(TOP_CONTAINER_ID, topContainerAfter);
+ final DataTreeCandidateTip prepare = prepareModification(dataTree, dataTreeModification);
+
+ final Map<YangInstanceIdentifier, ModificationDiff.NormalizedNodeUpdate> updates = getModificationDiff(prepare).getUpdates();
+ assertThat(updates.size(), is(1));
+ assertThat(updates.values().size(), is(1));
+ assertUpdate(updates.values().iterator().next(), TOP_CONTAINER_ID, topContainer, topContainerAfter);
+ }
+
+ @Test
+ public void testUpdateDelete() throws Exception {
+ final TipProducingDataTree dataTree = getDataTree();
+ final ContainerNode topContainer = getTopContainer("string1");
+ addNodeToTree(dataTree, topContainer, TOP_CONTAINER_ID);
+
+ final DataTreeModification dataTreeModification = getModification(dataTree);
+ dataTreeModification.delete(TOP_CONTAINER_ID);
+ final DataTreeCandidateTip prepare = prepareModification(dataTree, dataTreeModification);
+
+ final Map<YangInstanceIdentifier, ModificationDiff.NormalizedNodeUpdate> updates = getModificationDiff(prepare).getUpdates();
+ assertThat(updates.size(), is(1));
+ assertThat(updates.values().size(), is(1));
+ assertUpdate(updates.values().iterator().next(), TOP_CONTAINER_ID, topContainer, null);
+ }
+
+ @Test
+ public void testWriteAndUpdateInnerList() throws Exception {
+ final TipProducingDataTree dataTree = getDataTree();
+
+ DataTreeSnapshot dataTreeSnapshot = dataTree.takeSnapshot();
+ DataTreeModification dataTreeModification = dataTreeSnapshot.newModification();
+ final YangInstanceIdentifier listId =
+ YangInstanceIdentifier.create(
+ new YangInstanceIdentifier.NodeIdentifier(TOP_CONTAINER_QNAME),
+ new YangInstanceIdentifier.NodeIdentifier(NESTED_LIST_QNAME));
+
+ final MapNode mapNode = getNestedList("name1", "text");
+ final YangInstanceIdentifier listEntryId = listId.node(mapNode.getValue().iterator().next().getIdentifier());
+ dataTreeModification.write(listId, mapNode);
+ dataTreeModification.ready();
+ dataTree.validate(dataTreeModification);
+ DataTreeCandidateTip prepare = dataTree.prepare(dataTreeModification);
+
+ Map<YangInstanceIdentifier, ModificationDiff.NormalizedNodeUpdate> updates = getModificationDiff(prepare).getUpdates();
+
+ assertThat(updates.size(), is(1));
+ assertUpdate(getNormalizedNodeUpdateForAfterType(updates, MapEntryNode.class),
+ listEntryId, null, mapNode.getValue().iterator().next());
+
+ // Commit so that update can be tested next
+ dataTree.commit(prepare);
+
+ YangInstanceIdentifier listItemId = listId.node(
+ new YangInstanceIdentifier.NodeIdentifierWithPredicates(NESTED_LIST_QNAME, NAME_LEAF_QNAME, "name1"));
+ MapEntryNode mapEntryNode =
+ getNestedList("name1", "text-update").getValue().iterator().next();
+
+ dataTreeSnapshot = dataTree.takeSnapshot();
+ dataTreeModification = dataTreeSnapshot.newModification();
+ dataTreeModification.write(listItemId, mapEntryNode);
+ dataTreeModification.ready();
+ dataTree.validate(dataTreeModification);
+ prepare = dataTree.prepare(dataTreeModification);
+
+ updates = getModificationDiff(prepare).getUpdates();
+ assertThat(updates.size(), is(1 /*Actual list entry*/));
+ }
+//
+ private void assertUpdate(final ModificationDiff.NormalizedNodeUpdate update,
+ final YangInstanceIdentifier idExpected,
+ final NormalizedNode<?, ?> beforeExpected,
+ final NormalizedNode<?, ?> afterExpected) {
+ assertThat(update.getId(), is(idExpected));
+ assertThat(update.getDataBefore(), is(beforeExpected));
+ assertThat(update.getDataAfter(), is(afterExpected));
+ }
+
+ @Test
+ public void testWriteTopContainerAndInnerList() throws Exception {
+ final TipProducingDataTree dataTree = getDataTree();
+
+ DataTreeSnapshot dataTreeSnapshot = dataTree.takeSnapshot();
+ DataTreeModification dataTreeModification = dataTreeSnapshot.newModification();
+
+ final ContainerNode topContainer = getTopContainer("string1");
+ dataTreeModification.write(TOP_CONTAINER_ID, topContainer);
+
+ final YangInstanceIdentifier listId =
+ YangInstanceIdentifier.create(
+ new YangInstanceIdentifier.NodeIdentifier(TOP_CONTAINER_QNAME),
+ new YangInstanceIdentifier.NodeIdentifier(NESTED_LIST_QNAME));
+
+ final MapNode mapNode = getNestedList("name1", "text");
+ final YangInstanceIdentifier listEntryId = listId.node(mapNode.getValue().iterator().next().getIdentifier());
+
+ dataTreeModification.write(listId, mapNode);
+
+ final DataTreeCandidateTip prepare = prepareModification(dataTree, dataTreeModification);
+
+ final Map<YangInstanceIdentifier, ModificationDiff.NormalizedNodeUpdate> updates = getModificationDiff(prepare).getUpdates();
+
+ assertThat(updates.size(), is(2));
+ assertThat(updates.values().size(), is(2));
+ assertUpdate(getNormalizedNodeUpdateForAfterType(updates, ContainerNode.class), TOP_CONTAINER_ID, null,
+ Builders.containerBuilder(topContainer).withChild(mapNode).build());
+ assertUpdate(getNormalizedNodeUpdateForAfterType(updates, MapEntryNode.class), listEntryId, null, mapNode.getValue().iterator().next());
+ // Assert that keys of the updates map are not wildcarded YID
+ assertThat(updates.keySet(), hasItems(
+ TOP_CONTAINER_ID,
+ listEntryId));
+ }
+
+ private ModificationDiff.NormalizedNodeUpdate getNormalizedNodeUpdateForAfterType(
+ final Map<YangInstanceIdentifier, ModificationDiff.NormalizedNodeUpdate> updates,
+ final Class<? extends NormalizedNode<?, ?>> containerNodeClass) {
+ return updates.values().stream()
+ .filter(update -> containerNodeClass.isAssignableFrom(update.getDataAfter().getClass()))
+ .findFirst().get();
+ }
+
+ private ModificationDiff.NormalizedNodeUpdate getNormalizedNodeUpdateForBeforeType(
+ final Map<YangInstanceIdentifier, ModificationDiff.NormalizedNodeUpdate> updates,
+ final Class<? extends NormalizedNode<?, ?>> containerNodeClass) {
+ return updates.values().stream()
+ .filter(update -> containerNodeClass.isAssignableFrom(update.getDataBefore().getClass()))
+ .findFirst().get();
+ }
+
+ @Test
+ public void testWriteDeepList() throws Exception {
+ final TipProducingDataTree dataTree = getDataTree();
+
+ DataTreeSnapshot dataTreeSnapshot = dataTree.takeSnapshot();
+ DataTreeModification dataTreeModification = dataTreeSnapshot.newModification();
+
+ YangInstanceIdentifier listId =
+ YangInstanceIdentifier.create(
+ new YangInstanceIdentifier.NodeIdentifier(TOP_CONTAINER_QNAME),
+ new YangInstanceIdentifier.NodeIdentifier(NESTED_LIST_QNAME));
+
+ MapNode mapNode = getNestedList("name1", "text");
+ dataTreeModification.write(listId, mapNode);
+
+ dataTreeModification.ready();
+ dataTree.validate(dataTreeModification);
+ DataTreeCandidateTip prepare = dataTree.prepare(dataTreeModification);
+ dataTree.commit(prepare);
+
+ dataTreeSnapshot = dataTree.takeSnapshot();
+ dataTreeModification = dataTreeSnapshot.newModification();
+
+ final YangInstanceIdentifier.NodeIdentifierWithPredicates nestedListNodeId =
+ new YangInstanceIdentifier.NodeIdentifierWithPredicates(NESTED_LIST_QNAME, NAME_LEAF_QNAME, "name1");
+ listId = YangInstanceIdentifier.create(
+ new YangInstanceIdentifier.NodeIdentifier(TOP_CONTAINER_QNAME),
+ new YangInstanceIdentifier.NodeIdentifier(NESTED_LIST_QNAME),
+ nestedListNodeId);
+ final YangInstanceIdentifier deepListId =
+ listId.node(new YangInstanceIdentifier.NodeIdentifier(DEEP_LIST_QNAME));
+ final YangInstanceIdentifier deepListEntryId = deepListId.node(
+ new YangInstanceIdentifier.NodeIdentifierWithPredicates(DEEP_LIST_QNAME, NAME_LEAF_QNAME, "name1"));
+
+ final MapEntryNode deepListEntry = getDeepList("name1").getValue().iterator().next();
+ // Merge parent list, just to see no modifications on it
+ dataTreeModification.merge(
+ listId,
+ Builders.mapEntryBuilder().withNodeIdentifier(nestedListNodeId)
+ .withChild(ImmutableNodes.leafNode(NAME_LEAF_QNAME, "name1")).build());
+ dataTreeModification.merge(
+ deepListId,
+ Builders.mapBuilder()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(DEEP_LIST_QNAME))
+ .build());
+ dataTreeModification.merge(
+ deepListEntryId,
+ deepListEntry);
+
+ dataTreeModification.ready();
+ dataTree.validate(dataTreeModification);
+ prepare = dataTree.prepare(dataTreeModification);
+ dataTree.commit(prepare);
+
+ final Map<YangInstanceIdentifier, ModificationDiff.NormalizedNodeUpdate> updates = getModificationDiff(prepare).getUpdates();
+ assertThat(updates.size(), is(1));
+ assertUpdate(getNormalizedNodeUpdateForAfterType(updates, MapEntryNode.class), deepListEntryId, null, deepListEntry);
+ }
+
+ @Test
+ public void testDeleteInnerListItem() throws Exception {
+ final TipProducingDataTree dataTree = getDataTree();
+
+ DataTreeSnapshot dataTreeSnapshot = dataTree.takeSnapshot();
+ DataTreeModification dataTreeModification = dataTreeSnapshot.newModification();
+ final YangInstanceIdentifier listId =
+ YangInstanceIdentifier.create(
+ new YangInstanceIdentifier.NodeIdentifier(TOP_CONTAINER_QNAME),
+ new YangInstanceIdentifier.NodeIdentifier(NESTED_LIST_QNAME));
+
+ final MapNode mapNode = getNestedList("name1", "text");
+ dataTreeModification.write(listId, mapNode);
+ dataTreeModification.ready();
+ dataTree.validate(dataTreeModification);
+ DataTreeCandidateTip prepare = dataTree.prepare(dataTreeModification);
+
+ // Commit so that update can be tested next
+ dataTree.commit(prepare);
+
+ YangInstanceIdentifier listItemId = listId.node(
+ new YangInstanceIdentifier.NodeIdentifierWithPredicates(NESTED_LIST_QNAME, NAME_LEAF_QNAME, "name1"));
+
+ dataTreeSnapshot = dataTree.takeSnapshot();
+ dataTreeModification = dataTreeSnapshot.newModification();
+ dataTreeModification.delete(listItemId);
+ dataTreeModification.ready();
+ dataTree.validate(dataTreeModification);
+ prepare = dataTree.prepare(dataTreeModification);
+
+ final Map<YangInstanceIdentifier, ModificationDiff.NormalizedNodeUpdate> updates = getModificationDiff(prepare).getUpdates();
+ assertThat(updates.size(), is(1));
+ assertUpdate(getNormalizedNodeUpdateForBeforeType(updates, MapEntryNode.class), listItemId, mapNode.getValue().iterator().next(), null);
+ }
+
+ static void addNodeToTree(final DataTree dataTree, final NormalizedNode<?, ?> node,
+ final YangInstanceIdentifier id)
+ throws DataValidationFailedException {
+ DataTreeSnapshot dataTreeSnapshot = dataTree.takeSnapshot();
+ DataTreeModification dataTreeModification = dataTreeSnapshot.newModification();
+ dataTreeModification.write(id, node);
+ dataTreeModification.ready();
+ dataTree.validate(dataTreeModification);
+ DataTreeCandidate prepare = dataTree.prepare(dataTreeModification);
+ dataTree.commit(prepare);
+ }
+
+ static TipProducingDataTree getDataTree() throws ReactorException {
+ final TipProducingDataTree dataTree = InMemoryDataTreeFactory.getInstance().create(TreeType.CONFIGURATION);
+ dataTree.setSchemaContext(getSchemaCtx());
+ return dataTree;
+ }
+
+ static ContainerNode getTopContainer(final String stringValue) {
+ return Builders.containerBuilder()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TOP_CONTAINER_QNAME))
+ .withChild(ImmutableNodes.leafNode(STRING_LEAF_QNAME, stringValue))
+ .build();
+ }
+
+ static MapNode getNestedList(final String listItemName, final String text) {
+ return Builders.mapBuilder()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(NESTED_LIST_QNAME))
+ .withChild(
+ Builders.mapEntryBuilder()
+ .withNodeIdentifier(
+ new YangInstanceIdentifier.NodeIdentifierWithPredicates(NESTED_LIST_QNAME,
+ NAME_LEAF_QNAME, listItemName))
+ .withChild(ImmutableNodes.leafNode(NAME_LEAF_QNAME, listItemName))
+ .withChild(ImmutableNodes.leafNode(TEXT_LEAF_QNAME, text))
+ .build()
+ )
+ .build();
+ }
+
+ private MapNode getDeepList(final String listItemName) {
+ return Builders.mapBuilder()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(DEEP_LIST_QNAME))
+ .withChild(
+ Builders.mapEntryBuilder()
+ .withNodeIdentifier(
+ new YangInstanceIdentifier.NodeIdentifierWithPredicates(DEEP_LIST_QNAME,
+ NAME_LEAF_QNAME, listItemName))
+ .withChild(ImmutableNodes.leafNode(NAME_LEAF_QNAME, listItemName))
+ .build()
+ )
+ .build();
+ }
+
+ private static SchemaContext getSchemaCtx() throws ReactorException {
+ final CrossSourceStatementReactor.BuildAction buildAction = YangInferencePipeline.RFC6020_REACTOR.newBuild();
+ buildAction.addSource(new YangStatementSourceImpl(ModificationDiffTest.class.getResourceAsStream("/test-diff.yang")));
+ return buildAction.buildEffective();
+ }
+} \ No newline at end of file
diff --git a/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapterTest.java b/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapterTest.java
new file mode 100644
index 0000000..523d9dd
--- /dev/null
+++ b/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/PersistingDataTreeAdapterTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.data.impl;
+
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.sal.core.api.model.SchemaService;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
+
+public class PersistingDataTreeAdapterTest {
+
+ @Mock
+ private DataTree delegatingDataTree;
+ @Mock
+ private SchemaService schemaService;
+ @Mock
+ private DataTreeSnapshot snapshot;
+
+ private Path tmpPersistFile;
+
+ private PersistingDataTreeAdapter persistingDataTreeAdapter;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ tmpPersistFile = Files.createTempFile("testing-hc-persistence", "json");
+ persistingDataTreeAdapter = new PersistingDataTreeAdapter(delegatingDataTree, schemaService, tmpPersistFile);
+ }
+
+ @Test
+ public void testNoPersistOnFailure() throws Exception {
+ doThrow(new IllegalStateException("testing errors")).when(delegatingDataTree).commit(any(DataTreeCandidate.class));
+
+ try {
+ persistingDataTreeAdapter.commit(null);
+ fail("Exception expected");
+ } catch (IllegalStateException e) {
+ verify(delegatingDataTree, times(0)).takeSnapshot();
+ verify(delegatingDataTree).commit(any(DataTreeCandidate.class));
+ }
+ }
+
+} \ No newline at end of file
diff --git a/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransactionTest.java b/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransactionTest.java
new file mode 100644
index 0000000..a136217
--- /dev/null
+++ b/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransactionTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.data.impl;
+
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import io.fd.honeycomb.v3po.data.ReadableDataManager;
+import io.fd.honeycomb.v3po.data.DataModification;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public class ReadOnlyTransactionTest {
+
+ @Mock
+ private ReadableDataManager operationalData;
+ @Mock
+ private DataModification configSnapshot;
+
+ private ReadOnlyTransaction readOnlyTx;
+
+ @Before
+ public void setUp() {
+ initMocks(this);
+ readOnlyTx = ReadOnlyTransaction.create(configSnapshot, operationalData);
+ }
+
+ @Test
+ public void testExists() {
+ final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class);
+ final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException>
+ future = mock(CheckedFuture.class);
+ when(operationalData.read(path)).thenReturn(future);
+
+ readOnlyTx.exists(LogicalDatastoreType.OPERATIONAL, path);
+
+ verify(operationalData).read(path);
+ }
+
+ @Test
+ public void testGetIdentifier() {
+ assertNotNull(readOnlyTx.getIdentifier());
+ }
+} \ No newline at end of file
diff --git a/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadWriteTransactionTest.java b/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadWriteTransactionTest.java
new file mode 100644
index 0000000..1b67cd9
--- /dev/null
+++ b/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadWriteTransactionTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.data.impl;
+
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.verify;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public class ReadWriteTransactionTest {
+
+ @Mock
+ private DOMDataReadOnlyTransaction readTx;
+
+ @Mock
+ private DOMDataWriteTransaction writeTx;
+
+ private LogicalDatastoreType store;
+
+ @Mock
+ private YangInstanceIdentifier path;
+
+ @Mock
+ private NormalizedNode<?, ?> data;
+
+ private ReadWriteTransaction readWriteTx;
+
+ @Before
+ public void setUp() {
+ initMocks(this);
+ store = LogicalDatastoreType.CONFIGURATION;
+ readWriteTx = new ReadWriteTransaction(readTx, writeTx);
+ }
+
+ @Test
+ public void testCancel() {
+ readWriteTx.cancel();
+ verify(writeTx).cancel();
+ }
+
+ @Test
+ public void testPut() {
+ readWriteTx.put(store, path, data);
+ verify(writeTx).put(store, path, data);
+ }
+
+ @Test
+ public void testMerge() {
+ readWriteTx.merge(store, path, data);
+ verify(writeTx).merge(store, path, data);
+ }
+
+ @Test
+ public void testDelete() {
+ readWriteTx.delete(store, path);
+ verify(writeTx).delete(store, path);
+ }
+
+ @Test
+ public void testSubmit() throws Exception {
+ readWriteTx.submit();
+ verify(writeTx).submit();
+ }
+
+
+ @SuppressWarnings("deprecation")
+ @Test
+ public void testCommit() throws Exception {
+ readWriteTx.commit();
+ verify(writeTx).commit();
+ }
+
+ @Test
+ public void testRead() {
+ readWriteTx.read(store, path);
+ verify(readTx).read(store, path);
+ }
+
+ @Test
+ public void testExists() {
+ readWriteTx.exists(store, path);
+ verify(readTx).exists(store, path);
+ }
+
+ @Test
+ public void testGetIdentifier() throws Exception {
+ assertNotNull(readWriteTx.getIdentifier());
+ }
+} \ No newline at end of file
diff --git a/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadableDataTreeDelegatorTest.java b/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadableDataTreeDelegatorTest.java
new file mode 100644
index 0000000..455050a
--- /dev/null
+++ b/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadableDataTreeDelegatorTest.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.data.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.LinkedListMultimap;
+import com.google.common.collect.Multimap;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import io.fd.honeycomb.v3po.translate.read.ReadContext;
+import io.fd.honeycomb.v3po.translate.read.registry.ReaderRegistry;
+import java.util.Collections;
+import java.util.Map;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
+import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
+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.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public class ReadableDataTreeDelegatorTest {
+
+ @Mock
+ private BindingNormalizedNodeSerializer serializer;
+ @Mock
+ private ReaderRegistry reader;
+
+ private ReadableDataTreeDelegator operationalData;
+
+ @Mock
+ private InstanceIdentifier<DataObject> id;
+ @Mock
+ private Map.Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> entry;
+ @Mock
+ private SchemaContext globalContext;
+ @Mock
+ private DataSchemaNode schemaNode;
+ @Mock
+ private ReadContext readCtx;
+ @Mock
+ private DOMDataBroker netconfMonitoringBroker;
+ @Mock
+ private DOMDataReadOnlyTransaction domDataReadOnlyTransaction;
+ @Mock
+ private DataBroker contextBroker;
+
+ @Before
+ public void setUp() {
+ initMocks(this);
+ operationalData = new ReadableDataTreeDelegator(serializer, globalContext, reader, contextBroker);
+ doReturn(schemaNode).when(globalContext).getDataChildByName(any(QName.class));
+
+ doReturn(domDataReadOnlyTransaction).when(netconfMonitoringBroker).newReadOnlyTransaction();
+ doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(domDataReadOnlyTransaction)
+ .read(any(LogicalDatastoreType.class), any(YangInstanceIdentifier.class));
+
+ final org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction ctxTransaction = mock(
+ org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction.class);
+ doReturn(ctxTransaction).when(contextBroker).newReadWriteTransaction();
+ doReturn(Futures.immediateCheckedFuture(null)).when(ctxTransaction).submit();
+ }
+
+ @Test
+ public void testReadNode() throws Exception {
+ final YangInstanceIdentifier yangId = mock(YangInstanceIdentifier.class);
+ final YangInstanceIdentifier.PathArgument pArg = mock(YangInstanceIdentifier.PathArgument.class);
+ doReturn(pArg).when(yangId).getLastPathArgument();
+ doReturn(Collections.singletonList(pArg)).when(yangId).getPathArguments();
+
+ doReturn(QName.create("namespace", "2012-12-12", "local")).when(pArg).getNodeType();
+ doReturn(id).when(serializer).fromYangInstanceIdentifier(yangId);
+
+ final DataObject dataObject = mock(DataObject.class);
+ doReturn(Optional.of(dataObject)).when(reader).read(same(id), any(ReadContext.class));
+
+ when(serializer.toNormalizedNode(id, dataObject)).thenReturn(entry);
+ final DataContainerChild<?, ?> expectedValue = mock(DataContainerChild.class);
+ doReturn(expectedValue).when(entry).getValue();
+
+ final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> future = operationalData.read(yangId);
+
+ verify(serializer).fromYangInstanceIdentifier(yangId);
+ verify(reader).read(same(id), any(ReadContext.class));
+ final Optional<NormalizedNode<?, ?>> result = future.get();
+ assertTrue(result.isPresent());
+ assertEquals(expectedValue, result.get());
+ }
+
+ @Test
+ public void testReadNonExistingNode() throws Exception {
+ final YangInstanceIdentifier yangId = mock(YangInstanceIdentifier.class);
+ doReturn(id).when(serializer).fromYangInstanceIdentifier(yangId);
+ doReturn(Optional.absent()).when(reader).read(same(id), any(ReadContext.class));
+
+ final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> future = operationalData.read(yangId);
+
+ verify(serializer).fromYangInstanceIdentifier(yangId);
+ verify(reader).read(same(id), any(ReadContext.class));
+ final Optional<NormalizedNode<?, ?>> result = future.get();
+ assertFalse(result.isPresent());
+ }
+
+ @Test
+ public void testReadFailed() throws Exception {
+ doThrow(io.fd.honeycomb.v3po.translate.read.ReadFailedException.class).when(reader).readAll(any(ReadContext.class));
+
+ final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> future =
+ operationalData.read( YangInstanceIdentifier.EMPTY);
+
+ try {
+ future.checkedGet();
+ } catch (ReadFailedException e) {
+ assertTrue(e.getCause() instanceof io.fd.honeycomb.v3po.translate.read.ReadFailedException);
+ return;
+ }
+ fail("ReadFailedException was expected");
+ }
+
+ @Test
+ public void testReadRootWithOneNonListElement() throws Exception {
+ // Prepare data
+ final InstanceIdentifier<DataObject> vppStateII = InstanceIdentifier.create(DataObject.class);
+ final DataObject vppState = mock(DataObject.class);
+ Multimap<InstanceIdentifier<?>, DataObject> dataObjects = LinkedListMultimap.create();
+ dataObjects.put(vppStateII, vppState);
+ doReturn(dataObjects).when(reader).readAll(any(ReadContext.class));
+
+ // Init serializer
+ final YangInstanceIdentifier vppYangId = YangInstanceIdentifier.builder().node(QName.create("n", "d")).build();
+ when(serializer.toYangInstanceIdentifier(vppStateII)).thenReturn(vppYangId);
+ when(serializer.toNormalizedNode(vppStateII, vppState)).thenReturn(entry);
+ final DataContainerChild<?, ?> vppStateContainer = mock(DataContainerChild.class);
+ doReturn(vppStateContainer).when(entry).getValue();
+ doReturn(vppYangId.getLastPathArgument()).when(vppStateContainer).getIdentifier();
+
+ // Read root
+ final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> future =
+ operationalData.read(YangInstanceIdentifier.EMPTY);
+
+ verify(reader).readAll(any(ReadContext.class));
+ verify(serializer).toYangInstanceIdentifier(vppStateII);
+ verify(serializer).toNormalizedNode(vppStateII, vppState);
+
+ // Check the result is an ContainerNode with only one child
+ final Optional<NormalizedNode<?, ?>> result = future.get();
+ assertTrue(result.isPresent());
+
+ final ContainerNode rootNode = (ContainerNode) result.get();
+ assertEquals(SchemaContext.NAME, rootNode.getIdentifier().getNodeType());
+ assertEquals(vppStateContainer, Iterables.getOnlyElement(rootNode.getValue()));
+ }
+} \ No newline at end of file
diff --git a/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/WriteTransactionTest.java b/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/WriteTransactionTest.java
new file mode 100644
index 0000000..9cde27d
--- /dev/null
+++ b/infra/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/WriteTransactionTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.data.impl;
+
+import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import com.google.common.util.concurrent.CheckedFuture;
+import io.fd.honeycomb.v3po.data.DataModification;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
+
+public class WriteTransactionTest {
+
+ @Mock
+ private DataModification configSnapshot;
+ @Mock
+ private YangInstanceIdentifier path;
+ @Mock
+ private NormalizedNode<?,?> data;
+
+ private WriteTransaction writeTx;
+
+ @Before
+ public void setUp() {
+ initMocks(this);
+ writeTx = WriteTransaction.createConfigOnly(configSnapshot);
+ }
+
+ @Test
+ public void testPut() {
+ writeTx.put(LogicalDatastoreType.CONFIGURATION, path, data);
+ verify(configSnapshot).write(path, data);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testPutOperational() {
+ writeTx.put(LogicalDatastoreType.OPERATIONAL, path, data);
+ verify(configSnapshot).write(path, data);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testOnFinishedTx() {
+ writeTx.submit();
+ writeTx.put(LogicalDatastoreType.CONFIGURATION, path, data);
+ verify(configSnapshot).write(path, data);
+ }
+
+ @Test
+ public void testMerge() {
+ writeTx.merge(LogicalDatastoreType.CONFIGURATION, path, data);
+ verify(configSnapshot).merge(path, data);
+ }
+
+ @Test
+ public void testCancel() {
+ assertTrue(writeTx.cancel());
+ }
+
+ @Test
+ public void testCancelFinished() {
+ writeTx.submit();
+ assertFalse(writeTx.cancel());
+ }
+
+ @Test
+ public void testDelete() {
+ writeTx.delete(LogicalDatastoreType.CONFIGURATION, path);
+ verify(configSnapshot).delete(path);
+ }
+
+ @Test
+ public void testSubmit() throws Exception {
+ writeTx.submit();
+ verify(configSnapshot).validate();
+ verify(configSnapshot).commit();
+ }
+
+ @Test
+ public void testSubmitFailed() throws Exception {
+ doThrow(mock(DataValidationFailedException.class)).when(configSnapshot).commit();
+ final CheckedFuture<Void, TransactionCommitFailedException> future = writeTx.submit();
+ try {
+ future.get();
+ } catch (Exception e) {
+ assertTrue(e.getCause() instanceof TransactionCommitFailedException);
+ return;
+ }
+ fail("Expected exception to be thrown");
+
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testCommit() {
+ writeTx.commit();
+ }
+
+ @Test
+ public void testGetIdentifier() {
+ assertNotNull(writeTx.getIdentifier());
+ }
+} \ No newline at end of file
diff --git a/infra/data-impl/src/test/resources/test-diff.yang b/infra/data-impl/src/test/resources/test-diff.yang
new file mode 100644
index 0000000..5cccc87
--- /dev/null
+++ b/infra/data-impl/src/test/resources/test-diff.yang
@@ -0,0 +1,54 @@
+module test-diff {
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:test:diff";
+ prefix "td";
+
+ revision "2015-01-05" {
+ description "Initial revision";
+ }
+
+ container top-container {
+ leaf string {
+ type string;
+ }
+
+ list nested-list {
+ key "name";
+
+ leaf name {
+ type string;
+ }
+
+ leaf text {
+ type string;
+ }
+
+ list deep-list {
+ key "name";
+
+ leaf name {
+ type string;
+ }
+
+ }
+ }
+ }
+
+ container with-choice {
+
+ choice choice {
+ case case1 {
+ leaf in-case1 {
+ type string;
+ }
+ }
+
+ case case2 {
+ leaf in-case2 {
+ type string;
+ }
+ }
+ }
+ }
+
+}
diff --git a/infra/features/pom.xml b/infra/features/pom.xml
new file mode 100644
index 0000000..732c6ca
--- /dev/null
+++ b/infra/features/pom.xml
@@ -0,0 +1,217 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<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">
+ <parent>
+ <groupId>io.fd.honeycomb.common</groupId>
+ <artifactId>features-parent</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <relativePath>../../common/features-parent</relativePath>
+ </parent>
+ <groupId>io.fd.honeycomb</groupId>
+ <artifactId>honeycomb-features</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <name>${project.artifactId}</name>
+ <modelVersion>4.0.0</modelVersion>
+ <prerequisites>
+ <maven>3.1.1</maven>
+ </prerequisites>
+ <properties>
+ <mdsal.model.version>0.8.2-Beryllium-SR2</mdsal.model.version>
+ <mdsal.version>1.3.2-Beryllium-SR2</mdsal.version>
+ <restconf.version>1.3.2-Beryllium-SR2</restconf.version>
+ <netconf.version>1.0.2-Beryllium-SR2</netconf.version>
+ <yangtools.version>0.8.2-Beryllium-SR2</yangtools.version>
+ <dlux.version>0.3.2-Beryllium-SR2</dlux.version>
+ <configfile.directory>etc/opendaylight/karaf</configfile.directory>
+ </properties>
+ <dependencyManagement>
+ <dependencies>
+ <!-- project specific dependencies -->
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>mdsal-artifacts</artifactId>
+ <version>${mdsal.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.netconf</groupId>
+ <artifactId>restconf-artifacts</artifactId>
+ <version>${restconf.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.netconf</groupId>
+ <artifactId>netconf-artifacts</artifactId>
+ <version>${netconf.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>features-yangtools</artifactId>
+ <classifier>features</classifier>
+ <version>${yangtools.version}</version>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal.model</groupId>
+ <artifactId>features-mdsal-model</artifactId>
+ <version>${mdsal.model.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>features-mdsal</artifactId>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.netconf</groupId>
+ <artifactId>features-restconf</artifactId>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.netconf</groupId>
+ <artifactId>features-netconf-connector</artifactId>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.dlux</groupId>
+ <artifactId>features-dlux</artifactId>
+ <classifier>features</classifier>
+ <version>${dlux.version}</version>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>honeycomb-impl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>honeycomb-impl</artifactId>
+ <version>${project.version}</version>
+ <type>xml</type>
+ <classifier>config</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>honeycomb-impl</artifactId>
+ <version>${project.version}</version>
+ <type>xml</type>
+ <classifier>netconf</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>honeycomb-impl</artifactId>
+ <version>${project.version}</version>
+ <type>xml</type>
+ <classifier>init</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>honeycomb-impl</artifactId>
+ <version>${project.version}</version>
+ <type>xml</type>
+ <classifier>context</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>honeycomb-impl</artifactId>
+ <version>${project.version}</version>
+ <type>xml</type>
+ <classifier>restconf</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>data-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>data-impl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>notification-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>notification-impl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>notification-impl</artifactId>
+ <version>${project.version}</version>
+ <type>xml</type>
+ <classifier>config</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>notification-impl</artifactId>
+ <version>${project.version}</version>
+ <type>xml</type>
+ <classifier>notification2netconf</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>cfg-init</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>translate-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>translate-spi</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>translate-impl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>translate-utils</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jgrapht</groupId>
+ <artifactId>jgrapht-core</artifactId>
+ <version>0.9.2</version>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/infra/features/src/main/features/features.xml b/infra/features/src/main/features/features.xml
new file mode 100644
index 0000000..d0431d6
--- /dev/null
+++ b/infra/features/src/main/features/features.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<features name="odl-honeycomb-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
+ <repository>mvn:org.opendaylight.yangtools/features-yangtools/${yangtools.version}/xml/features</repository>
+ <repository>mvn:org.opendaylight.controller/features-mdsal/${mdsal.version}/xml/features</repository>
+ <repository>mvn:org.opendaylight.mdsal.model/features-mdsal-model/${mdsal.model.version}/xml/features</repository>
+ <repository>mvn:org.opendaylight.netconf/features-restconf/${restconf.version}/xml/features</repository>
+ <repository>mvn:org.opendaylight.netconf/features-netconf-connector/${netconf.version}/xml/features</repository>
+ <repository>mvn:org.opendaylight.dlux/features-dlux/${dlux.version}/xml/features</repository>
+
+ <feature name='odl-honeycomb-api' version='${project.version}' description='OpenDaylight :: honeycomb :: api'>
+ <feature version='${mdsal.model.version}'>odl-mdsal-models</feature>
+ </feature>
+
+ <feature name='odl-honeycomb' version='${project.version}' description='OpenDaylight :: honeycomb'>
+ <feature version='${mdsal.version}'>odl-mdsal-broker</feature>
+ <feature version='${project.version}'>odl-honeycomb-api</feature>
+ <!-- FIXME remove netconf-connector-ssh from features, only netconf northbound is needed -->
+ <feature version='${netconf.version}'>odl-netconf-connector-ssh</feature>
+ <feature version='${mdsal.version}'>odl-netconf-mdsal</feature>
+ <bundle>mvn:io.fd.honeycomb/honeycomb-impl/{{VERSION}}</bundle>
+ <bundle>mvn:io.fd.honeycomb/translate-api/{{VERSION}}</bundle>
+ <bundle>mvn:io.fd.honeycomb/translate-spi/{{VERSION}}</bundle>
+ <bundle>mvn:org.jgrapht/jgrapht-core/{{VERSION}}</bundle>
+ <bundle>mvn:io.fd.honeycomb/translate-utils/{{VERSION}}</bundle>
+ <bundle>mvn:io.fd.honeycomb/data-api/{{VERSION}}</bundle>
+ <bundle>mvn:io.fd.honeycomb/data-impl/{{VERSION}}</bundle>
+ <bundle>mvn:io.fd.honeycomb/notification-api/{{VERSION}}</bundle>
+ <bundle>mvn:io.fd.honeycomb/notification-impl/{{VERSION}}</bundle>
+ <bundle>mvn:io.fd.honeycomb/translate-impl/{{VERSION}}</bundle>
+ <bundle>mvn:io.fd.honeycomb/cfg-init/{{VERSION}}</bundle>
+ <configfile finalname="${configfile.directory}/honeycomb-context.xml">mvn:io.fd.honeycomb/honeycomb-impl/{{VERSION}}/xml/context</configfile>
+ <configfile finalname="${configfile.directory}/honeycomb-notification.xml">mvn:io.fd.honeycomb/notification-impl/{{VERSION}}/xml/config</configfile>
+ <configfile finalname="${configfile.directory}/honeycomb.xml">mvn:io.fd.honeycomb/honeycomb-impl/{{VERSION}}/xml/config</configfile>
+ <configfile finalname="${configfile.directory}/honeycomb-init.xml">mvn:io.fd.honeycomb/honeycomb-impl/{{VERSION}}/xml/init</configfile>
+ </feature>
+
+ <feature name='odl-honeycomb-rest' version='${project.version}' description='OpenDaylight :: honeycomb :: REST'>
+ <feature version="${project.version}">odl-honeycomb</feature>
+ <feature version="${restconf.version}">odl-restconf</feature>
+ <!-- Northbound interfaces configuration -->
+ <configfile finalname="${configfile.directory}/honeycomb-netconf.xml">mvn:io.fd.honeycomb/honeycomb-impl/{{VERSION}}/xml/netconf</configfile>
+ <configfile finalname="${configfile.directory}/honeycomb-notification2netconf.xml">mvn:io.fd.honeycomb/notification-impl/{{VERSION}}/xml/notification2netconf</configfile>
+ <configfile finalname="${configfile.directory}/honeycomb-restconf.xml">mvn:io.fd.honeycomb/honeycomb-impl/{{VERSION}}/xml/restconf</configfile>
+ </feature>
+
+ <feature name='odl-honeycomb-ui' version='${project.version}' description='OpenDaylight :: honeycomb :: UI'>
+ <feature version="${project.version}">odl-honeycomb-rest</feature>
+ <feature version="${restconf.version}">odl-mdsal-apidocs</feature>
+ <feature version="${mdsal.version}">odl-mdsal-xsql</feature>
+ <feature version="${dlux.version}">odl-dlux-yangui</feature>
+ </feature>
+
+</features>
diff --git a/infra/impl/pom.xml b/infra/impl/pom.xml
new file mode 100644
index 0000000..4a316ce
--- /dev/null
+++ b/infra/impl/pom.xml
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<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">
+
+ <parent>
+ <groupId>io.fd.honeycomb.common</groupId>
+ <artifactId>impl-parent</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <relativePath>../../common/impl-parent</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>io.fd.honeycomb</groupId>
+ <artifactId>honeycomb-impl</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>notification-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>translate-impl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>data-impl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>cfg-init</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <!-- TODO used by NetconfMonitoringReaderModule, get it out of here-->
+ <dependency>
+ <groupId>org.opendaylight.netconf</groupId>
+ <artifactId>ietf-netconf-monitoring</artifactId>
+ <version>1.0.2-Beryllium-SR2</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.netconf</groupId>
+ <artifactId>ietf-netconf-monitoring-extension</artifactId>
+ <version>1.0.2-Beryllium-SR2</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.opendaylight.mdsal.model</groupId>
+ <artifactId>ietf-topology</artifactId>
+ </dependency>
+
+ <!-- Testing Dependencies -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-artifacts</id>
+ <goals>
+ <goal>attach-artifact</goal>
+ </goals>
+ <phase>package</phase>
+ <configuration>
+ <artifacts>
+ <artifact>
+ <file>${config.file}</file>
+ <type>xml</type>
+ <classifier>config</classifier>
+ </artifact>
+ <artifact>
+ <file>src/main/config/netconf-north-config.xml</file>
+ <type>xml</type>
+ <classifier>netconf</classifier>
+ </artifact>
+ <artifact>
+ <file>src/main/config/initializer-config.xml</file>
+ <type>xml</type>
+ <classifier>init</classifier>
+ </artifact>
+ <artifact>
+ <file>src/main/config/context-datatree-config.xml</file>
+ <type>xml</type>
+ <classifier>context</classifier>
+ </artifact>
+ <artifact>
+ <file>src/main/config/restconf-north-config.xml</file>
+ <type>xml</type>
+ <classifier>restconf</classifier>
+ </artifact>
+ </artifacts>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/infra/impl/src/main/config/context-datatree-config.xml b/infra/impl/src/main/config/context-datatree-config.xml
new file mode 100644
index 0000000..313f0eb
--- /dev/null
+++ b/infra/impl/src/main/config/context-datatree-config.xml
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (c) 2016 Cisco and/or its affiliates.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at:
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+
+<snapshot>
+ <required-capabilities>
+ <capability>urn:opendaylight:params:xml:ns:yang:v3po:impl?module=v3po-impl&amp;revision=2014-12-10</capability>
+ <capability>urn:honeycomb:params:xml:ns:yang:translate:utils?module=translate-utils&amp;revision=2016-04-06</capability>
+ <capability>urn:honeycomb:params:xml:ns:yang:vpp:data:init?module=vpp-cfg-init&amp;revision=2016-04-07</capability>
+ <capability>urn:honeycomb:params:xml:ns:yang:data:api?module=data-api&amp;revision=2016-04-11</capability>
+ <capability>urn:honeycomb:params:xml:ns:yang:data:impl?module=data-impl&amp;revision=2016-04-11</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&amp;revision=2013-10-28</capability>
+ </required-capabilities>
+ <configuration>
+
+ <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+
+ <!-- TODO provide information stored in context data-tree to users as part of operational data -->
+ <!-- In-memory data tree for context(special data required for YANG <-> VPP mapping) data -->
+ <module>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:impl">prefix:inmemory-data-tree</type>
+ <name>inmemory-context-data-tree</name>
+ <schema-service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+ <name>yang-schema-service</name>
+ </schema-service>
+ <type xmlns="urn:honeycomb:params:xml:ns:yang:data:impl">oper</type>
+ </module>
+
+ <!-- DataTree adapter with persistence for context DT -->
+ <module>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:impl">prefix:persisting-data-tree-adapter</type>
+ <name>inmemory-persisted-context-data-tree</name>
+ <delegate>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:data-tree</type>
+ <name>inmemory-context-data-tree</name>
+ </delegate>
+ <schema-service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+ <name>yang-schema-service</name>
+ </schema-service>
+ <persist-file-path>etc/opendaylight/honeycomb/context.json</persist-file-path>
+ </module>
+
+ <!-- DOM Data Broker for context data -->
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:v3po:impl">prefix:honeycomb-context-dom-data-broker</type>
+ <name>honeycomb-context-data-broker</name>
+ <!-- With persistence -->
+ <context-data-tree>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:data-tree</type>
+ <name>inmemory-persisted-context-data-tree</name>
+ </context-data-tree>
+ </module>
+
+ <!-- BA Data Broker for context data -->
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-forwarded-data-broker</type>
+ <name>honeycomb-context-binding-data-broker</name>
+ <binding-forwarded-data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+ <dom-async-broker>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
+ <name>honeycomb-context-data-broker</name>
+ </dom-async-broker>
+ <schema-service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+ <name>yang-schema-service</name>
+ </schema-service>
+ <binding-mapping-service>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type>
+ <name>runtime-mapping-singleton</name>
+ </binding-mapping-service>
+ </binding-forwarded-data-broker>
+ </module>
+
+ <!-- Mapping context on top of BA context broker. Utilized by eg notification producers -->
+ <module>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:utils">prefix:realtime-mapping-context</type>
+ <name>realtime-mapping-context</name>
+ <context-binding-broker>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type>
+ <name>honeycomb-context-binding-data-broker</name>
+ </context-binding-broker>
+ </module>
+ </modules>
+
+ <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <service>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:data-tree</type>
+ <instance>
+ <name>inmemory-context-data-tree</name>
+ <provider>/modules/module[type='inmemory-data-tree'][name='inmemory-context-data-tree']
+ </provider>
+ </instance>
+ <instance>
+ <name>inmemory-persisted-context-data-tree</name>
+ <provider>/modules/module[type='persisting-data-tree-adapter'][name='inmemory-persisted-context-data-tree']
+ </provider>
+ </instance>
+ </service>
+
+ <service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
+ <instance>
+ <name>honeycomb-context-data-broker</name>
+ <provider>/modules/module[type='honeycomb-context-dom-data-broker'][name='honeycomb-context-data-broker']</provider>
+ </instance>
+ </service>
+
+ <service>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type>
+ <instance>
+ <name>honeycomb-context-binding-data-broker</name>
+ <provider>/modules/module[type='binding-forwarded-data-broker'][name='honeycomb-context-binding-data-broker']</provider>
+ </instance>
+ </service>
+
+ <service>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:api">prefix:honeycomb-mapping-context</type>
+ <instance>
+ <name>realtime-mapping-context</name>
+ <provider>/modules/module[type='realtime-mapping-context'][name='realtime-mapping-context']</provider>
+ </instance>
+ </service>
+ </services>
+ </data>
+ </configuration>
+</snapshot>
diff --git a/infra/impl/src/main/config/default-config.xml b/infra/impl/src/main/config/default-config.xml
new file mode 100644
index 0000000..c817a5d
--- /dev/null
+++ b/infra/impl/src/main/config/default-config.xml
@@ -0,0 +1,253 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<snapshot>
+ <required-capabilities>
+ <capability>urn:opendaylight:params:xml:ns:yang:v3po:impl?module=v3po-impl&amp;revision=2014-12-10</capability>
+ <capability>urn:honeycomb:params:xml:ns:yang:translate:utils?module=translate-utils&amp;revision=2016-04-06</capability>
+ <capability>urn:honeycomb:params:xml:ns:yang:data:api?module=data-api&amp;revision=2016-04-11</capability>
+ <capability>urn:honeycomb:params:xml:ns:yang:data:impl?module=data-impl&amp;revision=2016-04-11</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&amp;revision=2013-10-28</capability>
+ </required-capabilities>
+ <configuration>
+
+ <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+
+ <module>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:utils">prefix:delegating-reader-registry</type>
+ <name>read-registry</name>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:utils">prefix:delegating-writer-registry</type>
+ <name>write-registry</name>
+ </module>
+
+ <!-- In-memory data tree for HC config data tree -->
+ <module>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:impl">prefix:inmemory-data-tree</type>
+ <name>inmemory-config-data-tree</name>
+ <schema-service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+ <name>yang-schema-service</name>
+ </schema-service>
+ <type xmlns="urn:honeycomb:params:xml:ns:yang:data:impl">config</type>
+ </module>
+
+ <!-- DataTree adapter with persistence for config DT -->
+ <module>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:impl">prefix:persisting-data-tree-adapter</type>
+ <name>inmemory-persisted-config-data-tree</name>
+ <delegate>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:data-tree</type>
+ <name>inmemory-config-data-tree</name>
+ </delegate>
+ <schema-service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+ <name>yang-schema-service</name>
+ </schema-service>
+ <persist-file-path>etc/opendaylight/honeycomb/config.json</persist-file-path>
+ </module>
+
+
+ <!-- HC config data tree -->
+ <module>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:impl">prefix:honeycomb-config-data-tree</type>
+ <name>config-data-tree</name>
+ <!-- Without persistence -->
+ <!--<data-tree>-->
+ <!--<type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:impl">prefix:data-tree</type>-->
+ <!--<name>inmemory-config-data-tree</name>-->
+ <!--</data-tree>-->
+ <!-- With persistence -->
+ <data-tree>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:data-tree</type>
+ <name>inmemory-persisted-config-data-tree</name>
+ </data-tree>
+
+ <serializer>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-dom-mapping-service</type>
+ <name>runtime-mapping-singleton</name>
+ </serializer>
+ <writer-registry-builder>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:api">prefix:honeycomb-writer-registry-builder</type>
+ <name>write-registry-builder</name>
+ </writer-registry-builder>
+ <context-binding-broker>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type>
+ <name>honeycomb-context-binding-data-broker</name>
+ </context-binding-broker>
+ </module>
+
+ <!-- HC operational data tree -->
+ <module>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:impl">prefix:honeycomb-operational-data-tree</type>
+ <name>operational-data-tree</name>
+ <schema-service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+ <name>yang-schema-service</name>
+ </schema-service>
+ <serializer>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-dom-mapping-service</type>
+ <name>runtime-mapping-singleton</name>
+ </serializer>
+ <reader-registry-builder>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:api">prefix:honeycomb-reader-registry</type>
+ <name>read-registry</name>
+ </reader-registry-builder>
+ <context-binding-broker>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type>
+ <name>honeycomb-context-binding-data-broker</name>
+ </context-binding-broker>
+ </module>
+
+ <!-- DOM data broker which provides transaction functionality for HC using BI format-->
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:v3po:impl">prefix:honeycomb-dom-data-broker</type>
+ <name>honeycomb-dom-data-broker</name>
+ <config-data-tree>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:honeycomb-modifiable-data-tree</type>
+ <name>config-data-tree</name>
+ </config-data-tree>
+ <operational-data-tree>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:honeycomb-readable-data-tree</type>
+ <name>operational-data-tree</name>
+ </operational-data-tree>
+ </module>
+
+ <!-- Binding data broker which provides transaction functionality for HC using BA format -->
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-forwarded-data-broker</type>
+ <name>honeycomb-binding-data-broker</name>
+ <binding-forwarded-data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+
+ <dom-async-broker>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
+ <name>honeycomb-dom-data-broker</name>
+ </dom-async-broker>
+ <schema-service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+ <name>yang-schema-service</name>
+ </schema-service>
+ <binding-mapping-service>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type>
+ <name>runtime-mapping-singleton</name>
+ </binding-mapping-service>
+ </binding-forwarded-data-broker>
+ </module>
+
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:v3po:impl">prefix:v3po</type>
+ <name>v3po-default</name>
+ <dom-broker>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">prefix:dom-broker-osgi-registry</type>
+ <name>dom-broker</name>
+ </dom-broker>
+ <honeycomb-dom-data-broker>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">prefix:dom-async-data-broker</type>
+ <name>honeycomb-dom-data-broker</name>
+ </honeycomb-dom-data-broker>
+ <honeycomb-dom-notification-service>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:notification:api">prefix:dom-notification-service</type>
+ <name>honeycomb-dom-notification-service</name>
+ </honeycomb-dom-notification-service>
+ </module>
+ </modules>
+
+ <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+
+ <service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
+ <instance>
+ <name>honeycomb-dom-data-broker</name>
+ <provider>/modules/module[type='honeycomb-dom-data-broker'][name='honeycomb-dom-data-broker']</provider>
+ </instance>
+ </service>
+
+ <service>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type>
+ <instance>
+ <name>honeycomb-binding-data-broker</name>
+ <provider>/modules/module[type='binding-forwarded-data-broker'][name='honeycomb-binding-data-broker']</provider>
+ </instance>
+ </service>
+
+ <service>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:api">prefix:honeycomb-reader-registry</type>
+ <instance>
+ <name>read-registry</name>
+ <provider>/modules/module[type='delegating-reader-registry'][name='read-registry']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:api">prefix:honeycomb-writer-registry</type>
+ <instance>
+ <name>write-registry</name>
+ <provider>/modules/module[type='delegating-writer-registry'][name='write-registry']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:api">prefix:honeycomb-writer-registry-builder</type>
+ <instance>
+ <name>write-registry-builder</name>
+ <provider>/modules/module[type='delegating-writer-registry'][name='write-registry']</provider>
+ </instance>
+ </service>
+
+ <service>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:data-tree</type>
+ <instance>
+ <name>inmemory-config-data-tree</name>
+ <provider>/modules/module[type='inmemory-data-tree'][name='inmemory-config-data-tree']
+ </provider>
+ </instance>
+ <instance>
+ <name>inmemory-persisted-config-data-tree</name>
+ <provider>/modules/module[type='persisting-data-tree-adapter'][name='inmemory-persisted-config-data-tree']
+ </provider>
+ </instance>
+ </service>
+
+ <service>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:honeycomb-modifiable-data-tree</type>
+ <instance>
+ <name>config-data-tree</name>
+ <provider>/modules/module[type='honeycomb-config-data-tree'][name='config-data-tree']
+ </provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:honeycomb-readable-data-tree</type>
+ <instance>
+ <name>operational-data-tree</name>
+ <provider>/modules/module[type='honeycomb-operational-data-tree'][name='operational-data-tree']
+ </provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
+ dom:dom-broker-osgi-registry
+ </type>
+ <instance>
+ <name>vpp-dom-broker</name>
+ <provider>/modules/module[type='v3po'][name='v3po-default']</provider>
+ </instance>
+ </service>
+
+ </services>
+ </data>
+ </configuration>
+</snapshot>
diff --git a/infra/impl/src/main/config/initializer-config.xml b/infra/impl/src/main/config/initializer-config.xml
new file mode 100644
index 0000000..f460693
--- /dev/null
+++ b/infra/impl/src/main/config/initializer-config.xml
@@ -0,0 +1,188 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (c) 2016 Cisco and/or its affiliates.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at:
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+
+<snapshot>
+ <required-capabilities>
+ <capability>urn:opendaylight:params:xml:ns:yang:v3po:impl?module=v3po-impl&amp;revision=2014-12-10</capability>
+ <capability>urn:honeycomb:params:xml:ns:yang:translate:utils?module=translate-utils&amp;revision=2016-04-06</capability>
+ <capability>urn:honeycomb:params:xml:ns:yang:vpp:data:init?module=vpp-cfg-init&amp;revision=2016-04-07</capability>
+ <capability>urn:honeycomb:params:xml:ns:yang:data:api?module=data-api&amp;revision=2016-04-11</capability>
+ <capability>urn:honeycomb:params:xml:ns:yang:data:impl?module=data-impl&amp;revision=2016-04-11</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&amp;revision=2013-10-28</capability>
+ </required-capabilities>
+ <configuration>
+
+ <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <!-- Config initialization -->
+ <!-- Empty registry which does not pass data to VPP -->
+ <module>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:utils">prefix:noop-writer-registry-builder</type>
+ <name>noop-writer-registry-builder</name>
+ </module>
+ <!-- Config data tree which does not pass data to translation layer (uses noop-write-registry) -->
+ <module>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:impl">prefix:honeycomb-config-data-tree</type>
+ <name>cfg-init-config-data-tree</name>
+ <!-- Without persistence -->
+ <data-tree>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:data-tree</type>
+ <name>inmemory-config-data-tree</name>
+ </data-tree>
+ <serializer>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-dom-mapping-service</type>
+ <name>runtime-mapping-singleton</name>
+ </serializer>
+ <writer-registry-builder>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:api">prefix:honeycomb-writer-registry-builder</type>
+ <name>noop-writer-registry-builder</name>
+ </writer-registry-builder>
+ <context-binding-broker>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type>
+ <name>honeycomb-context-binding-data-broker</name>
+ </context-binding-broker>
+ </module>
+ <!-- DOM data broker for config initialization -->
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:v3po:impl">prefix:honeycomb-dom-data-broker</type>
+ <name>cfg-init-dom-data-broker</name>
+ <config-data-tree>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:honeycomb-modifiable-data-tree</type>
+ <name>cfg-init-config-data-tree</name>
+ </config-data-tree>
+ <operational-data-tree>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:honeycomb-readable-data-tree</type>
+ <name>operational-data-tree</name>
+ </operational-data-tree>
+ </module>
+ <!-- Binding data broker for config initialization -->
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-forwarded-data-broker</type>
+ <name>cfg-init-binding-data-broker</name>
+ <binding-forwarded-data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+ <dom-async-broker>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
+ <name>cfg-init-dom-data-broker</name>
+ </dom-async-broker>
+ <schema-service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+ <name>yang-schema-service</name>
+ </schema-service>
+ <binding-mapping-service>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type>
+ <name>runtime-mapping-singleton</name>
+ </binding-mapping-service>
+ </binding-forwarded-data-broker>
+ </module>
+
+ <module>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:data:init">prefix:persisted-file-initializer</type>
+ <name>persisted-context-initializer</name>
+ <dom-data-broker>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
+ <name>honeycomb-context-data-broker</name>
+ </dom-data-broker>
+ <schema-service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+ <name>yang-schema-service</name>
+ </schema-service>
+ <persist-file-path>etc/opendaylight/honeycomb/context.json</persist-file-path>
+ <restoration-type>merge</restoration-type>
+ <datastore-type>oper</datastore-type>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:data:init">prefix:persisted-file-initializer</type>
+ <name>persisted-config-initializer</name>
+ <dom-data-broker>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">prefix:dom-async-data-broker</type>
+ <name>honeycomb-dom-data-broker</name>
+ </dom-data-broker>
+ <schema-service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+ <name>yang-schema-service</name>
+ </schema-service>
+ <persist-file-path>etc/opendaylight/honeycomb/config.json</persist-file-path>
+ <restoration-type>merge</restoration-type>
+ <datastore-type>config</datastore-type>
+ </module>
+
+ <module>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:data:init">prefix:cfg-initializer-registry</type>
+ <name>initializer-registry</name>
+ <persisted-context-initializer>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:data:init">prefix:cfg-initializer</type>
+ <name>persisted-context-initializer</name>
+ </persisted-context-initializer>
+ <persisted-config-initializer>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:data:init">prefix:cfg-initializer</type>
+ <name>persisted-config-initializer</name>
+ </persisted-config-initializer>
+ </module>
+ <!-- END: Config initialization -->
+ </modules>
+
+ <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <!-- Config initialization -->
+ <service>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:api">prefix:honeycomb-writer-registry-builder</type>
+ <instance>
+ <name>noop-writer-registry-builder</name>
+ <provider>/modules/module[type='noop-writer-registry-builder'][name='noop-writer-registry-builder']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:data:api">prefix:honeycomb-modifiable-data-tree</type>
+ <instance>
+ <name>cfg-init-config-data-tree</name>
+ <provider>/modules/module[type='honeycomb-config-data-tree'][name='cfg-init-config-data-tree']
+ </provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
+ <instance>
+ <name>cfg-init-dom-data-broker</name>
+ <provider>/modules/module[type='honeycomb-dom-data-broker'][name='cfg-init-dom-data-broker']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type>
+ <instance>
+ <name>cfg-init-binding-data-broker</name>
+ <provider>/modules/module[type='binding-forwarded-data-broker'][name='cfg-init-binding-data-broker']</provider>
+ </instance>
+ </service>
+
+ <service>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:vpp:data:init">prefix:cfg-initializer</type>
+ <instance>
+ <name>persisted-context-initializer</name>
+ <provider>/modules/module[type='persisted-file-initializer'][name='persisted-context-initializer']
+ </provider>
+ </instance>
+ <instance>
+ <name>persisted-config-initializer</name>
+ <provider>/modules/module[type='persisted-file-initializer'][name='persisted-config-initializer']
+ </provider>
+ </instance>
+ </service>
+ </services>
+ </data>
+ </configuration>
+</snapshot>
diff --git a/infra/impl/src/main/config/netconf-north-config.xml b/infra/impl/src/main/config/netconf-north-config.xml
new file mode 100644
index 0000000..35bd5ff
--- /dev/null
+++ b/infra/impl/src/main/config/netconf-north-config.xml
@@ -0,0 +1,496 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (c) 2016 Cisco and/or its affiliates.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at:
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+
+<snapshot>
+ <configuration>
+ <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+
+ <!-- In memory DS dedicated to NETCONF monitoring, notifications etc. -->
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:inmemory-datastore-provider">prefix:inmemory-config-datastore-provider</type>
+ <name>netconf-config-store-service</name>
+ <inmemory-config-datastore-provider xmlns="urn:opendaylight:params:xml:ns:yang:controller:inmemory-datastore-provider">
+ <schema-service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+ <name>yang-schema-service</name>
+ </schema-service>
+ </inmemory-config-datastore-provider>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:inmemory-datastore-provider">prefix:inmemory-operational-datastore-provider</type>
+ <name>netconf-operational-store-service</name>
+ <inmemory-operational-datastore-provider xmlns="urn:opendaylight:params:xml:ns:yang:controller:inmemory-datastore-provider">
+ <schema-service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+ <name>yang-schema-service</name>
+ </schema-service>
+ </inmemory-operational-datastore-provider>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-inmemory-data-broker</type>
+ <name>netconf-inmemory-data-broker</name>
+
+ <schema-service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+ <name>yang-schema-service</name>
+ </schema-service>
+
+ <config-data-store>
+ <type xmlns:config-dom-store-spi="urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:config-dom-store">config-dom-store-spi:config-dom-datastore</type>
+ <name>netconf-config-store-service</name>
+ </config-data-store>
+
+ <operational-data-store>
+ <type xmlns:operational-dom-store-spi="urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:operational-dom-store">operational-dom-store-spi:operational-dom-datastore</type>
+ <name>netconf-operational-store-service</name>
+ </operational-data-store>
+ </module>
+
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-forwarded-data-broker</type>
+ <name>netconf-binding-data-broker</name>
+ <binding-forwarded-data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+ <dom-async-broker>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
+ <name>netconf-inmemory-data-broker</name>
+ </dom-async-broker>
+ <schema-service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+ <name>yang-schema-service</name>
+ </schema-service>
+ <binding-mapping-service>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type>
+ <name>runtime-mapping-singleton</name>
+ </binding-mapping-service>
+ </binding-forwarded-data-broker>
+ </module>
+ <module>
+ <!--binding-broker-osgi-registry-->
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:v3po:impl">prefix:binding-broker-netconf</type>
+ <name>binding-broker-netconf</name>
+ <netconf-binding-broker>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type>
+ <name>netconf-binding-data-broker</name>
+ </netconf-binding-broker>
+ </module>
+ <!-- END:In memory DS dedicated to NETCONF monitoring, notifications etc. -->
+
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:mapper">
+ prefix:netconf-mdsal-mapper
+ </type>
+ <name>netconf-vpp-mapper</name>
+ <root-schema-service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service
+ </type>
+ <name>yang-schema-service</name>
+ </root-schema-service>
+ <root-schema-source-provider>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
+ dom:yang-text-source-provider
+ </type>
+ <name>yang-text-source-provider</name>
+ </root-schema-source-provider>
+ <dom-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:mapper">
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
+ dom:dom-broker-osgi-registry
+ </type>
+ <name>vpp-dom-broker</name>
+ </dom-broker>
+ <mapper-aggregator xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:mapper">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:north:mapper">
+ prefix:netconf-mapper-registry
+ </type>
+ <name>vpp-mapper-aggregator-registry</name>
+ </mapper-aggregator>
+ </module>
+
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound:impl">
+ prefix:netconf-server-dispatcher-impl
+ </type>
+ <name>netconf-vpp-server-dispatcher</name>
+ <mappers xmlns="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound:impl">
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:netconf:north:mapper">
+ dom:netconf-northbound-mapper
+ </type>
+ <name>vpp-mapper-aggregator</name>
+ </mappers>
+ <server-monitor
+ xmlns="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound:impl">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound">
+ prefix:netconf-server-monitoring
+ </type>
+ <name>vpp-server-monitor</name>
+ </server-monitor>
+ <boss-thread-group
+ xmlns="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound:impl">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netty">
+ prefix:netty-threadgroup
+ </type>
+ <name>global-boss-group</name>
+ </boss-thread-group>
+ <worker-thread-group
+ xmlns="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound:impl">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netty">
+ prefix:netty-threadgroup
+ </type>
+ <name>global-worker-group</name>
+ </worker-thread-group>
+ <timer xmlns="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound:impl">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netty">prefix:netty-timer
+ </type>
+ <name>global-timer</name>
+ </timer>
+ </module>
+
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:monitoring">
+ prefix:netconf-mdsal-monitoring-mapper
+ </type>
+ <name>netconf-vpp-monitoring-mapper</name>
+ <server-monitoring xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:monitoring">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound">
+ prefix:netconf-server-monitoring
+ </type>
+ <name>vpp-server-monitor</name>
+ </server-monitoring>
+ <binding-aware-broker
+ xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:monitoring">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
+ prefix:binding-broker-osgi-registry
+ </type>
+ <name>binding-broker-netconf</name>
+ </binding-aware-broker>
+ <aggregator xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:monitoring">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:north:mapper">
+ prefix:netconf-mapper-registry
+ </type>
+ <name>vpp-mapper-aggregator-registry</name>
+ </aggregator>
+ </module>
+
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound:impl">
+ prefix:netconf-mapper-aggregator
+ </type>
+ <name>vpp-mapper-aggregator</name>
+ </module>
+
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound:impl">
+ prefix:netconf-server-monitoring-impl
+ </type>
+ <name>vpp-server-monitor</name>
+ <aggregator xmlns="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound:impl">
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:netconf:north:mapper">
+ dom:netconf-northbound-mapper
+ </type>
+ <name>vpp-mapper-aggregator</name>
+ </aggregator>
+ </module>
+
+ <!-- Change the port of global netconf north from 2830 to 2831, so that honeycomb netconf northbound can use 2830-->
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:ssh">prefix:netconf-northbound-ssh</type>
+ <name>netconf-mdsal-ssh-server</name>
+ <port xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:ssh">2831</port>
+ </module>
+
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:ssh">
+ prefix:netconf-northbound-ssh
+ </type>
+ <name>netconf-vpp-ssh-server</name>
+
+ <port xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:ssh">2830</port>
+ <event-executor xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:ssh">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netty">
+ prefix:netty-event-executor
+ </type>
+ <name>global-event-executor</name>
+ </event-executor>
+ <worker-thread-group xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:ssh">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netty">
+ prefix:netty-threadgroup
+ </type>
+ <name>global-worker-group</name>
+ </worker-thread-group>
+ <processing-executor xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:ssh">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:threadpool">
+ prefix:threadpool
+ </type>
+ <name>global-netconf-ssh-scheduled-executor</name>
+ </processing-executor>
+ <dispatcher xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:ssh">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound">
+ prefix:netconf-server-dispatcher
+ </type>
+ <name>netconf-vpp-server-dispatcher</name>
+ </dispatcher>
+ <auth-provider xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:ssh">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:auth">
+ prefix:netconf-auth-provider
+ </type>
+ <name>default-auth-provider</name>
+ </auth-provider>
+ </module>
+
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:notification:impl">
+ prefix:netconf-notification-manager
+ </type>
+ <name>vpp-netconf-notification-manager</name>
+ </module>
+
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:notification">
+ prefix:netconf-mdsal-notification-mapper
+ </type>
+ <name>netconf-vpp-notification-mapper</name>
+ <!--This is used to listen to netconf-state/capabilities changes to send out notifications-->
+ <data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:notification">
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
+ binding:binding-async-data-broker
+ </type>
+ <name>netconf-binding-data-broker</name>
+ </data-broker>
+ <!--This writes stream list into DS-->
+ <binding-aware-broker
+ xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:notification">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
+ prefix:binding-broker-osgi-registry
+ </type>
+ <name>binding-broker-netconf</name>
+ </binding-aware-broker>
+ <aggregator xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:notification">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:north:mapper">
+ prefix:netconf-mapper-registry
+ </type>
+ <name>vpp-mapper-aggregator-registry</name>
+ </aggregator>
+ <notification-registry
+ xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:notification">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:notification">
+ prefix:netconf-notification-registry
+ </type>
+ <name>vpp-netconf-notification-manager</name>
+ </notification-registry>
+ <notification-collector>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:notification">
+ prefix:netconf-notification-collector
+ </type>
+ <name>vpp-netconf-notification-manager</name>
+ </notification-collector>
+ </module>
+
+
+ <!--TCP endpoint for MD-SAL netconf server -->
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:tcp">
+ prefix:netconf-northbound-tcp
+ </type>
+ <name>netconf-vpp-tcp-server</name>
+ <dispatcher xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:tcp">
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound">
+ prefix:netconf-server-dispatcher
+ </type>
+ <name>netconf-vpp-server-dispatcher</name>
+ </dispatcher>
+ <port xmlns="urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:tcp">7777</port>
+ </module>
+
+ <!-- Special reader for Netconf monitoring. The problem is that we store netconf monitoring in a dedicated DS.
+ However netconf is wired to our reader registry, so we need to delegate the reads of netconf-monitoring
+ through our readers to the dedicated DS-->
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:v3po:impl">prefix:netconf-monitoring-reader</type>
+ <name>netconf-monitoring-reader</name>
+ <netconf-monitoring-binding-broker>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type>
+ <name>netconf-binding-data-broker</name>
+ </netconf-monitoring-binding-broker>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:utils">prefix:delegating-reader-registry</type>
+ <name>read-registry</name>
+ <reader-factory>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:api">prefix:honeycomb-reader-factory</type>
+ <name>netconf-monitoring-reader</name>
+ </reader-factory>
+ </module>
+ <!-- END: Special reader for Netconf monitoring. -->
+
+ </modules>
+
+ <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <service>
+ <type xmlns:config-dom-store-spi="urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:config-dom-store">config-dom-store-spi:config-dom-datastore</type>
+ <instance>
+ <name>netconf-config-store-service</name>
+ <provider>/modules/module[type='inmemory-config-datastore-provider'][name='netconf-config-store-service']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:operational-dom-store-spi="urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:operational-dom-store">operational-dom-store-spi:operational-dom-datastore</type>
+ <instance>
+ <name>netconf-operational-store-service</name>
+ <provider>/modules/module[type='inmemory-operational-datastore-provider'][name='netconf-operational-store-service']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
+ <instance>
+ <name>netconf-inmemory-data-broker</name>
+ <provider>/modules/module[type='dom-inmemory-data-broker'][name='netconf-inmemory-data-broker']</provider>
+ </instance>
+ </service>
+
+ <service>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:translate:api">prefix:honeycomb-reader-factory</type>
+ <instance>
+ <name>netconf-monitoring-reader</name>
+ <provider>/modules/module[type='netconf-monitoring-reader'][name='netconf-monitoring-reader']</provider>
+ </instance>
+ </service>
+
+ <!-- In memory DS dedicated to NETCONF monitoring, notifications etc. -->
+
+ <service>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type>
+ <instance>
+ <name>netconf-binding-data-broker</name>
+ <provider>/modules/module[type='binding-forwarded-data-broker'][name='netconf-binding-data-broker']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
+ <instance>
+ <name>binding-broker-netconf</name>
+ <provider>/modules/module[type='binding-broker-netconf'][name='binding-broker-netconf']</provider>
+ </instance>
+ </service>
+ <!-- END:In memory DS dedicated to NETCONF monitoring, notifications etc. -->
+
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound">
+ prefix:netconf-server-monitoring
+ </type>
+ <instance>
+ <name>vpp-server-monitor</name>
+ <provider>/modules/module[type='netconf-server-monitoring-impl'][name='vpp-server-monitor']
+ </provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:north:mapper">
+ prefix:netconf-northbound-mapper
+ </type>
+ <instance>
+ <name>netconf-vpp-mapper</name>
+ <provider>/modules/module[type='netconf-mdsal-mapper'][name='netconf-vpp-mapper']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:north:mapper">
+ prefix:netconf-northbound-mapper
+ </type>
+ <instance>
+ <name>vpp-mapper-aggregator</name>
+ <provider>/modules/module[type='netconf-mapper-aggregator'][name='vpp-mapper-aggregator']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:north:mapper">
+ prefix:netconf-mapper-registry
+ </type>
+ <instance>
+ <name>vpp-mapper-aggregator-registry</name>
+ <provider>/modules/module[type='netconf-mapper-aggregator'][name='vpp-mapper-aggregator']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound">
+ prefix:netconf-server-dispatcher
+ </type>
+ <instance>
+ <name>netconf-vpp-server-dispatcher</name>
+ <provider>
+ /modules/module[type='netconf-server-dispatcher-impl'][name='netconf-vpp-server-dispatcher']
+ </provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:north:mapper">
+ prefix:netconf-northbound-mapper
+ </type>
+ <instance>
+ <name>netconf-vpp-notification-mapper</name>
+ <provider>
+ /modules/module[type='netconf-mdsal-notification-mapper'][name='netconf-vpp-notification-mapper']
+ </provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:notification">
+ prefix:netconf-notification-collector
+ </type>
+ <instance>
+ <name>vpp-netconf-notification-manager</name>
+ <provider>
+ /modules/module[type='netconf-notification-manager'][name='vpp-netconf-notification-manager']
+ </provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:notification">
+ prefix:netconf-notification-registry
+ </type>
+ <instance>
+ <name>vpp-netconf-notification-manager</name>
+ <provider>
+ /modules/module[type='netconf-notification-manager'][name='vpp-netconf-notification-manager']
+ </provider>
+ </instance>
+ </service>
+ </services>
+
+ </data>
+ </configuration>
+ <required-capabilities>
+ <capability>urn:opendaylight:params:xml:ns:yang:v3po:impl?module=v3po-impl&amp;revision=2014-12-10</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&amp;revision=2013-10-28</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:mapper?module=netconf-mdsal-mapper&amp;revision=2015-01-14</capability>
+ <capability>
+ urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:monitoring?module=netconf-mdsal-monitoring&amp;revision=2015-02-18
+ </capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:ssh?module=netconf-northbound-ssh&amp;revision=2015-01-14</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:tcp?module=netconf-northbound-tcp&amp;revision=2015-04-23</capability>
+ <capability>
+ urn:opendaylight:params:xml:ns:yang:controller:config:netconf:northbound:impl?module=netconf-northbound-impl&amp;revision=2015-01-12
+ </capability>
+ <capability>
+ urn:opendaylight:params:xml:ns:yang:controller:threadpool:impl:scheduled?module=threadpool-impl-scheduled&amp;revision=2013-12-01
+ </capability>
+ <capability>
+ urn:opendaylight:params:xml:ns:yang:controller:netconf:mdsal:notification?module=netconf-mdsal-notification&amp;revision=2015-08-03
+ </capability>
+ </required-capabilities>
+</snapshot>
diff --git a/infra/impl/src/main/config/restconf-north-config.xml b/infra/impl/src/main/config/restconf-north-config.xml
new file mode 100644
index 0000000..ff2cdac
--- /dev/null
+++ b/infra/impl/src/main/config/restconf-north-config.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (c) 2016 Cisco and/or its affiliates.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at:
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<snapshot>
+ <configuration>
+ <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <module>
+ <type xmlns:rest="urn:opendaylight:params:xml:ns:yang:controller:md:sal:rest:connector">rest:rest-connector-impl</type>
+ <name>rest-connector-default-impl</name>
+ <!-- Reconfiguring the default restconf northbound instance, to wire it just to honeycomb broker facade -->
+ <dom-broker>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
+ <name>vpp-dom-broker</name>
+ </dom-broker>
+ </module>
+ </modules>
+ </data>
+ </configuration>
+ <required-capabilities>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:sal:restconf:service?module=sal-restconf-service&amp;revision=2015-07-08</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:rest:connector?module=opendaylight-rest-connector&amp;revision=2014-07-24</capability>
+ </required-capabilities>
+</snapshot>
diff --git a/infra/impl/src/main/java/io/fd/honeycomb/v3po/impl/NorthboundFacadeHoneycombDOMBroker.java b/infra/impl/src/main/java/io/fd/honeycomb/v3po/impl/NorthboundFacadeHoneycombDOMBroker.java
new file mode 100644
index 0000000..c2d70c3
--- /dev/null
+++ b/infra/impl/src/main/java/io/fd/honeycomb/v3po/impl/NorthboundFacadeHoneycombDOMBroker.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.impl;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Maps;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import java.util.Map;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.NotThreadSafe;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotificationPublishService;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcAvailabilityListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementationNotAvailableException;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.controller.sal.core.api.BrokerService;
+import org.opendaylight.controller.sal.core.api.Consumer;
+import org.opendaylight.controller.sal.core.api.Provider;
+import org.opendaylight.controller.sal.core.api.model.SchemaService;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionListener;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Implementation of dom broker to facade VPP pipeline for northbound APIs
+ */
+public class NorthboundFacadeHoneycombDOMBroker implements AutoCloseable, Broker {
+
+ private static final BrokerService EMPTY_DOM_RPC_SERVICE = new EmptyDomRpcService();
+ private static final BrokerService EMPTY_DOM_MOUNT_SERVICE = new EmptyDomMountService();
+
+ private Map<Class<? extends BrokerService>, BrokerService> services;
+
+ public NorthboundFacadeHoneycombDOMBroker(@Nonnull final DOMDataBroker domDataBrokerDependency,
+ @Nonnull final SchemaService schemaBiService,
+ @Nonnull final DOMNotificationService domNotificatioNService) {
+ services = Maps.newHashMap();
+ services.put(DOMDataBroker.class, domDataBrokerDependency);
+ // All services below are required to be present by Restconf northbound
+ services.put(SchemaService.class, schemaBiService);
+ services.put(DOMRpcService.class, EMPTY_DOM_RPC_SERVICE);
+ services.put(DOMMountPointService.class, EMPTY_DOM_MOUNT_SERVICE);
+ services.put(DOMNotificationService.class, domNotificatioNService);
+ // TODO do both notification service types have to be registered ?
+ services.put(DOMNotificationPublishService.class, domNotificatioNService);
+ }
+
+ @Override
+ public void close() throws Exception {
+ // NOOP
+ }
+
+ @Override
+ public ConsumerSession registerConsumer(final Consumer consumer) {
+ final SimpleConsumerSession session = new SimpleConsumerSession(services);
+ consumer.onSessionInitiated(session);
+ return session;
+ }
+
+ @Deprecated
+ @Override
+ public ConsumerSession registerConsumer(final Consumer consumer, final BundleContext bundleContext) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ProviderSession registerProvider(final Provider provider) {
+ final SimpleProviderSession session = new SimpleProviderSession(services);
+ provider.onSessionInitiated(session);
+ return session;
+ }
+
+ @Override
+ public ProviderSession registerProvider(final Provider provider, final BundleContext bundleContext) {
+ throw new UnsupportedOperationException();
+ }
+
+ @NotThreadSafe
+ private static class SimpleConsumerSession implements ConsumerSession {
+ private boolean closed;
+ private final Map<Class<? extends BrokerService>, BrokerService> services;
+
+ private SimpleConsumerSession(final Map<Class<? extends BrokerService>, BrokerService> services) {
+ this.services = services;
+ }
+
+ @Override
+ public boolean isClosed() {
+ return closed;
+ }
+
+ @Override
+ public <T extends BrokerService> T getService(final Class<T> aClass) {
+ return (T)services.get(aClass);
+ }
+
+ @Override
+ public void close() {
+ closed = true;
+ }
+ }
+
+ @NotThreadSafe
+ private static class SimpleProviderSession implements ProviderSession {
+ private boolean closed;
+ private final Map<Class<? extends BrokerService>, BrokerService> services;
+
+ private SimpleProviderSession(final Map<Class<? extends BrokerService>, BrokerService> services) {
+ this.services = services;
+ }
+
+ @Override
+ public boolean isClosed() {
+ return closed;
+ }
+
+ @Override
+ public <T extends BrokerService> T getService(final Class<T> aClass) {
+ return (T)services.get(aClass);
+ }
+
+ @Override
+ public void close() {
+ closed = true;
+ }
+ }
+
+ private static class EmptyDomRpcService implements DOMRpcService {
+ @Nonnull
+ @Override
+ public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(@Nonnull final SchemaPath schemaPath,
+ @Nullable final NormalizedNode<?, ?> normalizedNode) {
+ return Futures.<DOMRpcResult, DOMRpcException>immediateFailedCheckedFuture(
+ new DOMRpcImplementationNotAvailableException("RPCs not supported"));
+ }
+
+ @Nonnull
+ @Override
+ public <T extends DOMRpcAvailabilityListener> ListenerRegistration<T> registerRpcListener(@Nonnull final T t) {
+ return new ListenerRegistration<T>() {
+ @Override
+ public void close() {
+ // Noop
+ }
+
+ @Override
+ public T getInstance() {
+ return t;
+ }
+ };
+ }
+ }
+
+ private static class EmptyDomMountService implements DOMMountPointService {
+ @Override
+ public Optional<DOMMountPoint> getMountPoint(final YangInstanceIdentifier yangInstanceIdentifier) {
+ return Optional.absent();
+ }
+
+ @Override
+ public DOMMountPointBuilder createMountPoint(final YangInstanceIdentifier yangInstanceIdentifier) {
+ throw new UnsupportedOperationException("No mountpoint support");
+ }
+
+ @Override
+ public ListenerRegistration<MountProvisionListener> registerProvisionListener(
+ final MountProvisionListener mountProvisionListener) {
+ return new ListenerRegistration<MountProvisionListener>() {
+ @Override
+ public void close() {
+ // Noop
+ }
+
+ @Override
+ public MountProvisionListener getInstance() {
+ return mountProvisionListener;
+ }
+ };
+ }
+ }
+}
diff --git a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/ContextDataBrokerModule.java b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/ContextDataBrokerModule.java
new file mode 100644
index 0000000..1d1fa53
--- /dev/null
+++ b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/ContextDataBrokerModule.java
@@ -0,0 +1,26 @@
+package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210;
+
+import io.fd.honeycomb.v3po.data.impl.DataBroker;
+import io.fd.honeycomb.v3po.data.impl.ModifiableDataTreeManager;
+
+public class ContextDataBrokerModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.AbstractContextDataBrokerModule {
+
+ public ContextDataBrokerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public ContextDataBrokerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.ContextDataBrokerModule oldModule, java.lang.AutoCloseable oldInstance) {
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ public void customValidation() {
+ // add custom validation form module attributes here.
+ }
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+ return DataBroker.create(new ModifiableDataTreeManager(getContextDataTreeDependency()));
+ }
+
+}
diff --git a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/ContextDataBrokerModuleFactory.java b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/ContextDataBrokerModuleFactory.java
new file mode 100644
index 0000000..360f5f4
--- /dev/null
+++ b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/ContextDataBrokerModuleFactory.java
@@ -0,0 +1,13 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: v3po-impl yang module local name: honeycomb-context-dom-data-broker
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Mon May 16 15:27:12 CEST 2016
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210;
+public class ContextDataBrokerModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.AbstractContextDataBrokerModuleFactory {
+
+}
diff --git a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/DataBrokerModule.java b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/DataBrokerModule.java
new file mode 100644
index 0000000..8aa3d64
--- /dev/null
+++ b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/DataBrokerModule.java
@@ -0,0 +1,34 @@
+package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210;
+
+import io.fd.honeycomb.v3po.data.impl.DataBroker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DataBrokerModule extends
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.AbstractDataBrokerModule {
+
+ private static final Logger LOG = LoggerFactory.getLogger(DataBrokerModule.class);
+
+ public DataBrokerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier,
+ org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public DataBrokerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier,
+ org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.DataBrokerModule oldModule,
+ java.lang.AutoCloseable oldInstance) {
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ public void customValidation() {
+ // add custom validation form module attributes here.
+ }
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+ LOG.debug("DataBrokerModule.createInstance()");
+ return DataBroker.create(getConfigDataTreeDependency(), getOperationalDataTreeDependency());
+ }
+}
diff --git a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/DataBrokerModuleFactory.java b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/DataBrokerModuleFactory.java
new file mode 100644
index 0000000..cc30bea
--- /dev/null
+++ b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/DataBrokerModuleFactory.java
@@ -0,0 +1,13 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: v3po-impl yang module local name: honeycomb-dom-data-broker
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Mon Apr 11 07:53:38 CEST 2016
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210;
+public class DataBrokerModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.AbstractDataBrokerModuleFactory {
+
+}
diff --git a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfBindingBrokerModule.java b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfBindingBrokerModule.java
new file mode 100644
index 0000000..48d227d
--- /dev/null
+++ b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfBindingBrokerModule.java
@@ -0,0 +1,117 @@
+package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
+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.rpc.RpcContextIdentifier;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.osgi.framework.BundleContext;
+
+public class NetconfBindingBrokerModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.AbstractNetconfBindingBrokerModule {
+ public NetconfBindingBrokerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public NetconfBindingBrokerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.NetconfBindingBrokerModule oldModule, java.lang.AutoCloseable oldInstance) {
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ public void customValidation() {
+ // add custom validation form module attributes here.
+ }
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+ return new FakeBindingAwareBroker(getNetconfBindingBrokerDependency());
+ }
+
+ private static class FakeBindingAwareBroker implements BindingAwareBroker, AutoCloseable {
+
+ private DataBroker netconfBindingBrokerDependency;
+
+ public FakeBindingAwareBroker(final DataBroker netconfBindingBrokerDependency) {
+
+ this.netconfBindingBrokerDependency = netconfBindingBrokerDependency;
+ }
+
+ @Deprecated
+ @Override
+ public ConsumerContext registerConsumer(final BindingAwareConsumer bindingAwareConsumer,
+ final BundleContext bundleContext) {
+ throw new UnsupportedOperationException("Unsupported");
+ }
+
+ @Override
+ public ConsumerContext registerConsumer(final BindingAwareConsumer bindingAwareConsumer) {
+ final ConsumerContext consumerContext = new ConsumerContext() {
+ @Override
+ public <T extends BindingAwareService> T getSALService(final Class<T> aClass) {
+ return aClass.equals(DataBroker.class)
+ ? (T) netconfBindingBrokerDependency
+ : null;
+ }
+
+ @Override
+ public <T extends RpcService> T getRpcService(final Class<T> aClass) {
+ return null;
+ }
+ };
+ bindingAwareConsumer.onSessionInitialized(consumerContext);
+ return consumerContext;
+ }
+
+ @Override
+ public ProviderContext registerProvider(final BindingAwareProvider bindingAwareProvider,
+ final BundleContext bundleContext) {
+ throw new UnsupportedOperationException("Unsupported");
+ }
+
+ @Override
+ public ProviderContext registerProvider(final BindingAwareProvider bindingAwareProvider) {
+ final ProviderContext context = new ProviderContext() {
+ @Override
+ public <L extends RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>>> ListenerRegistration<L> registerRouteChangeListener(
+ final L l) {
+ throw new UnsupportedOperationException("Unsupported");
+ }
+
+ @Override
+ public <T extends RpcService> T getRpcService(final Class<T> aClass) {
+ throw new UnsupportedOperationException("Unsupported");
+ }
+
+ @Override
+ public <T extends RpcService> RpcRegistration<T> addRpcImplementation(final Class<T> aClass, final T t)
+ throws IllegalStateException {
+ throw new UnsupportedOperationException("Unsupported");
+ }
+
+ @Override
+ public <T extends RpcService> RoutedRpcRegistration<T> addRoutedRpcImplementation(
+ final Class<T> aClass, final T t) throws IllegalStateException {
+ throw new UnsupportedOperationException("Unsupported");
+ }
+
+ @Override
+ public <T extends BindingAwareService> T getSALService(final Class<T> aClass) {
+ return aClass.equals(DataBroker.class)
+ ? (T) netconfBindingBrokerDependency
+ : null; }
+ };
+ bindingAwareProvider.onSessionInitiated(context);
+ return context;
+ }
+
+ @Override
+ public void close() throws Exception {
+ netconfBindingBrokerDependency = null;
+ }
+ }
+}
+
diff --git a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfBindingBrokerModuleFactory.java b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfBindingBrokerModuleFactory.java
new file mode 100644
index 0000000..b64b0b1
--- /dev/null
+++ b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfBindingBrokerModuleFactory.java
@@ -0,0 +1,13 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: v3po-impl yang module local name: binding-broker-netconf
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Wed Mar 23 10:45:48 CET 2016
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210;
+public class NetconfBindingBrokerModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.AbstractNetconfBindingBrokerModuleFactory {
+
+}
diff --git a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfMonitoringReaderModule.java b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfMonitoringReaderModule.java
new file mode 100644
index 0000000..8502fcb
--- /dev/null
+++ b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfMonitoringReaderModule.java
@@ -0,0 +1,46 @@
+package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210;
+
+import io.fd.honeycomb.v3po.translate.read.registry.ModifiableReaderRegistryBuilder;
+import io.fd.honeycomb.v3po.translate.util.read.BindingBrokerReader;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfStateBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class NetconfMonitoringReaderModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.AbstractNetconfMonitoringReaderModule {
+ public NetconfMonitoringReaderModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public NetconfMonitoringReaderModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.NetconfMonitoringReaderModule oldModule, java.lang.AutoCloseable oldInstance) {
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ public void customValidation() {
+ // add custom validation form module attributes here.
+ }
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+ return new ReaderFactory(getNetconfMonitoringBindingBrokerDependency());
+ }
+
+
+ private static final class ReaderFactory implements AutoCloseable, io.fd.honeycomb.v3po.translate.read.ReaderFactory {
+
+ private final DataBroker netconfMonitoringBindingBrokerDependency;
+
+ public ReaderFactory(final DataBroker netconfMonitoringBindingBrokerDependency) {
+ this.netconfMonitoringBindingBrokerDependency = netconfMonitoringBindingBrokerDependency;
+ }
+
+ @Override
+ public void init(final ModifiableReaderRegistryBuilder registry) {
+ registry.add(new BindingBrokerReader<>(InstanceIdentifier.create(NetconfState.class),
+ netconfMonitoringBindingBrokerDependency,
+ LogicalDatastoreType.OPERATIONAL, NetconfStateBuilder.class));
+ }
+ }
+}
diff --git a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfMonitoringReaderModuleFactory.java b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfMonitoringReaderModuleFactory.java
new file mode 100644
index 0000000..b8b7bec
--- /dev/null
+++ b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfMonitoringReaderModuleFactory.java
@@ -0,0 +1,13 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: v3po-impl yang module local name: netconf-monitoring-reader
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Tue Apr 12 13:03:40 CEST 2016
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210;
+public class NetconfMonitoringReaderModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.AbstractNetconfMonitoringReaderModuleFactory {
+
+}
diff --git a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModule.java b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModule.java
new file mode 100644
index 0000000..caa792d
--- /dev/null
+++ b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModule.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210;
+
+import io.fd.honeycomb.v3po.impl.NorthboundFacadeHoneycombDOMBroker;
+import org.opendaylight.controller.sal.core.api.AbstractProvider;
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.controller.sal.core.api.model.SchemaService;
+
+public class V3poModule extends
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.AbstractV3poModule {
+
+ public V3poModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier,
+ org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public V3poModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier,
+ org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.V3poModule oldModule,
+ java.lang.AutoCloseable oldInstance) {
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ public void customValidation() {
+ // add custom validation form module attributes here
+ }
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+
+ final Broker.ProviderSession providerSession =
+ getDomBrokerDependency().registerProvider(new AbstractProvider() {
+ @Override
+ public void onSessionInitiated(final Broker.ProviderSession providerSession) {
+ // NOOP
+ }
+ });
+ final SchemaService schemaBiService = providerSession.getService(SchemaService.class);
+
+ return new NorthboundFacadeHoneycombDOMBroker(getHoneycombDomDataBrokerDependency(), schemaBiService,
+ getHoneycombDomNotificationServiceDependency());
+ }
+
+}
diff --git a/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactory.java b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactory.java
new file mode 100644
index 0000000..5c94286
--- /dev/null
+++ b/infra/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactory.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+* Generated file
+*
+* Generated from: yang module name: v3po yang module local name: v3po
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Fri Jan 02 13:49:24 CST 2015
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210;
+public class V3poModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.AbstractV3poModuleFactory {
+
+}
diff --git a/infra/impl/src/main/yang/v3po-impl.yang b/infra/impl/src/main/yang/v3po-impl.yang
new file mode 100644
index 0000000..fa96706
--- /dev/null
+++ b/infra/impl/src/main/yang/v3po-impl.yang
@@ -0,0 +1,155 @@
+module v3po-impl {
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:v3po:impl";
+ prefix "v3po-impl";
+
+ import config { prefix config; revision-date 2013-04-05; }
+ import opendaylight-md-sal-binding { prefix md-sal-binding; revision-date 2013-10-28;}
+ import opendaylight-md-sal-dom {prefix dom;}
+ import translate-api { prefix tapi; revision-date 2016-04-06; }
+ import data-api { prefix dapi; revision-date 2016-04-11; }
+ import notification-api { prefix hc-notif-a; revision-date 2016-06-01; }
+
+ description
+ "Service definition for v3po project";
+
+ revision "2014-12-10" {
+ description
+ "Initial revision";
+ }
+
+ identity v3po {
+ base config:module-type;
+ config:provided-service dom:dom-broker-osgi-registry;
+ config:java-name-prefix V3po;
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case v3po {
+ when "/config:modules/config:module/config:type = 'v3po'";
+ container dom-broker {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity dom:dom-broker-osgi-registry;
+ }
+ }
+ }
+
+ container honeycomb-dom-data-broker {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity dom:dom-async-data-broker;
+ }
+ }
+ }
+
+ container honeycomb-dom-notification-service {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity hc-notif-a:dom-notification-service;
+ }
+ }
+ }
+
+ }
+ }
+
+ identity binding-broker-netconf {
+ base config:module-type;
+ config:provided-service md-sal-binding:binding-broker-osgi-registry;
+ config:java-name-prefix NetconfBindingBroker;
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case binding-broker-netconf {
+ when "/config:modules/config:module/config:type = 'binding-broker-netconf'";
+
+ container netconf-binding-broker {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity md-sal-binding:binding-async-data-broker;
+ }
+ }
+ }
+
+ }
+ }
+
+ identity honeycomb-dom-data-broker {
+ base config:module-type;
+ config:provided-service dom:dom-async-data-broker;
+ config:java-name-prefix DataBroker;
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case honeycomb-dom-data-broker {
+ when "/config:modules/config:module/config:type = 'honeycomb-dom-data-broker'";
+
+ container config-data-tree {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity dapi:honeycomb-modifiable-data-tree;
+ }
+ }
+ }
+
+ container operational-data-tree {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity dapi:honeycomb-readable-data-tree;
+ }
+ }
+ }
+
+ }
+ }
+
+ identity honeycomb-context-dom-data-broker {
+ base config:module-type;
+ config:provided-service dom:dom-async-data-broker;
+ config:java-name-prefix ContextDataBroker;
+ description "DomBroker on top of context data-tree";
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case honeycomb-context-dom-data-broker {
+ when "/config:modules/config:module/config:type = 'honeycomb-context-dom-data-broker'";
+
+ container context-data-tree {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity dapi:data-tree;
+ }
+ }
+ }
+ }
+ }
+
+ identity netconf-monitoring-reader {
+ base config:module-type;
+ config:provided-service tapi:honeycomb-reader-factory;
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case netconf-monitoring-reader {
+ when "/config:modules/config:module/config:type = 'netconf-monitoring-reader'";
+
+ container netconf-monitoring-binding-broker {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity md-sal-binding:binding-async-data-broker;
+ }
+ }
+ }
+
+ }
+ }
+}
diff --git a/infra/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactoryTest.java b/infra/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactoryTest.java
new file mode 100644
index 0000000..5b9a674
--- /dev/null
+++ b/infra/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactoryTest.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210;
+
+import org.junit.Test;
+
+public class V3poModuleFactoryTest {
+ @Test
+ public void testFactoryConstructor() {
+ // ensure no exceptions on construction
+ new V3poModuleFactory();
+ }
+}
diff --git a/infra/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleTest.java b/infra/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleTest.java
new file mode 100644
index 0000000..3d8e796
--- /dev/null
+++ b/infra/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import javax.management.ObjectName;
+import org.junit.Test;
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.opendaylight.controller.config.api.JmxAttribute;
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.controller.sal.core.api.Provider;
+import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
+
+public class V3poModuleTest {
+ @Test
+ public void testCustomValidation() {
+ V3poModule module = new V3poModule(mock(ModuleIdentifier.class), mock(DependencyResolver.class));
+
+ // ensure no exceptions on validation
+ // currently this method is empty
+ module.customValidation();
+ }
+
+ @Test
+ public void testCreateInstance() throws Exception {
+ // configure mocks
+ DependencyResolver dependencyResolver = mock(DependencyResolver.class);
+ BindingAwareBroker broker = mock(BindingAwareBroker.class);
+ when(dependencyResolver.resolveInstance(eq(BindingAwareBroker.class), any(ObjectName.class), any(JmxAttribute.class)))
+ .thenReturn(broker);
+ final org.opendaylight.controller.sal.core.api.Broker domBroker = mock(org.opendaylight.controller.sal.core.api.Broker.class);
+ when(dependencyResolver.resolveInstance(eq(org.opendaylight.controller.sal.core.api.Broker.class), any(ObjectName.class), any(JmxAttribute.class)))
+ .thenReturn(domBroker);
+ doReturn(mock(Broker.ProviderSession.class)).when(domBroker).registerProvider(any(Provider.class));
+ when(dependencyResolver.resolveInstance(eq(BindingNormalizedNodeSerializer.class), any(ObjectName.class), any(JmxAttribute.class)))
+ .thenReturn(mock(BindingNormalizedNodeSerializer.class));
+ when(dependencyResolver.resolveInstance(eq(DOMDataBroker.class), any(ObjectName.class), any(JmxAttribute.class)))
+ .thenReturn(mock(DOMDataBroker.class));
+
+ // create instance of module with injected mocks
+ V3poModule module = new V3poModule(mock(ModuleIdentifier.class), dependencyResolver);
+
+ // getInstance calls resolveInstance to get the broker dependency and then calls createInstance
+ AutoCloseable closeable = module.getInstance();
+
+ // ensure no exceptions on close
+ closeable.close();
+ }
+}
diff --git a/infra/it/it-test/pom.xml b/infra/it/it-test/pom.xml
new file mode 100644
index 0000000..c7a3103
--- /dev/null
+++ b/infra/it/it-test/pom.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2016 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<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">
+ <parent>
+ <artifactId>impl-parent</artifactId>
+ <groupId>io.fd.honeycomb.common</groupId>
+ <version>1.0.0-SNAPSHOT</version>
+ <relativePath>../../../common/impl-parent</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>io.fd.honeycomb</groupId>
+ <artifactId>honeycomb-it-test</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>data-impl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>translate-impl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.skinny-framework</groupId>
+ <artifactId>skinny-logback</artifactId>
+ <version>1.0.8</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>honeycomb-test-model</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+
+</project> \ No newline at end of file
diff --git a/infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/AbstractInfraTest.java b/infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/AbstractInfraTest.java
new file mode 100644
index 0000000..47644cc
--- /dev/null
+++ b/infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/AbstractInfraTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.data.impl;
+
+import static org.mockito.Mockito.when;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+import com.google.common.util.concurrent.Futures;
+import java.util.Collections;
+import java.util.Map;
+import javassist.ClassPool;
+import org.junit.Before;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.$YangModuleInfoImpl;
+import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.DataObjectSerializerGenerator;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
+import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
+import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+/**
+ * Base IT test infrastructure.
+ */
+abstract class AbstractInfraTest {
+
+ protected BindingNormalizedNodeSerializer serializer;
+ protected SchemaContext schemaContext;
+
+ @Mock
+ protected org.opendaylight.controller.md.sal.binding.api.DataBroker contextBroker;
+ @Mock
+ private org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction ctxTx;
+
+ static BindingToNormalizedNodeCodec getSerializer(final ModuleInfoBackedContext moduleInfoBackedContext,
+ final SchemaContext schemaContext) {
+ final DataObjectSerializerGenerator serializerGenerator = new StreamWriterGenerator(JavassistUtils.forClassPool(
+ ClassPool.getDefault()));
+ final BindingNormalizedNodeCodecRegistry codecRegistry = new BindingNormalizedNodeCodecRegistry(serializerGenerator);
+ final BindingRuntimeContext ctx =
+ BindingRuntimeContext.create(moduleInfoBackedContext, schemaContext);
+ codecRegistry.onBindingRuntimeContextUpdated(ctx);
+ return new BindingToNormalizedNodeCodec(moduleInfoBackedContext, codecRegistry);
+ }
+
+ static ModuleInfoBackedContext getSchemaContext() {
+ final ModuleInfoBackedContext moduleInfoBackedContext = ModuleInfoBackedContext.create();
+ moduleInfoBackedContext.addModuleInfos(Collections.singleton($YangModuleInfoImpl.getInstance()));
+ return moduleInfoBackedContext;
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ when(contextBroker.newReadWriteTransaction()).thenReturn(ctxTx);
+ when(ctxTx.submit()).thenReturn(Futures.immediateCheckedFuture(null));
+
+ initSerializer();
+ postSetup();
+ }
+
+ abstract void postSetup();
+
+ private void initSerializer() {
+ final ModuleInfoBackedContext moduleInfoBackedContext = getSchemaContext();
+ schemaContext = moduleInfoBackedContext.tryToCreateSchemaContext().get();
+ serializer = getSerializer(moduleInfoBackedContext, schemaContext);
+ }
+
+ protected Multimap<InstanceIdentifier<? extends DataObject>, ? extends DataObject> toBinding(
+ final NormalizedNode<?, ?> read) {
+ Multimap<InstanceIdentifier<? extends DataObject>, DataObject> baNodes = HashMultimap.create();
+
+ for (DataContainerChild<?, ?> o : ((DataContainerNode<?>) read).getValue()) {
+ final YangInstanceIdentifier yid = YangInstanceIdentifier.of(o.getNodeType());
+ final Map.Entry<InstanceIdentifier<?>, DataObject> baEntry = serializer.fromNormalizedNode(yid, o);
+ baNodes.put(baEntry.getKey(), baEntry.getValue());
+ }
+ return baNodes;
+ }
+}
diff --git a/infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombReadInfraTest.java b/infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombReadInfraTest.java
new file mode 100644
index 0000000..b1f3a19
--- /dev/null
+++ b/infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombReadInfraTest.java
@@ -0,0 +1,460 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.data.impl;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyListOf;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
+import com.google.common.util.concurrent.CheckedFuture;
+import io.fd.honeycomb.v3po.translate.impl.read.GenericListReader;
+import io.fd.honeycomb.v3po.translate.read.ListReader;
+import io.fd.honeycomb.v3po.translate.read.ReadContext;
+import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
+import io.fd.honeycomb.v3po.translate.read.Reader;
+import io.fd.honeycomb.v3po.translate.read.registry.ReaderRegistry;
+import io.fd.honeycomb.v3po.translate.util.RWUtils;
+import io.fd.honeycomb.v3po.translate.util.read.ReflexiveListReaderCustomizer;
+import io.fd.honeycomb.v3po.translate.util.read.ReflexiveReader;
+import io.fd.honeycomb.v3po.translate.util.read.registry.CompositeReaderRegistryBuilder;
+import java.lang.reflect.InvocationTargetException;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.junit.Test;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.exceptions.misusing.MockitoConfigurationException;
+import org.mockito.invocation.InvocationOnMock;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ComplexAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ComplexAugmentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleAugmentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleContainer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleContainerBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainerBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainerKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.container.in.list.NestedList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.container.in.list.NestedListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.container.in.list.NestedListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.simple.container.ComplexAugmentContainer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.simple.container.ComplexAugmentContainerBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public class HoneycombReadInfraTest extends AbstractInfraTest {
+
+ @Mock
+ private ReadContext ctx;
+ private ReaderRegistry registry;
+
+ // 1
+ private Reader<SimpleContainer, SimpleContainerBuilder> simpleContainerReader =
+ mockReader(Ids.SIMPLE_CONTAINER_ID, this::readSimpleContainer, SimpleContainerBuilder.class);
+ // 1.1
+ private Reader<SimpleAugment, SimpleAugmentBuilder> simpleAugmentReader =
+ mockReader(Ids.SIMPLE_AUGMENT_ID, this::readSimpleAugment, SimpleAugmentBuilder.class);
+ // 1.2
+ // Noop reader(no real attributes)
+ private Reader<ComplexAugment, ComplexAugmentBuilder> complexAugmentReader =
+ mockReader(Ids.COMPLEX_AUGMENT_ID, HoneycombReadInfraTest::noopRead, ComplexAugmentBuilder.class);
+ // 1.2.1
+ private Reader<ComplexAugmentContainer, ComplexAugmentContainerBuilder> complexAugmentContainerReader =
+ mockReader(Ids.COMPLEX_AUGMENT_CONTAINER_ID, this::readComplexAugmentContainer, ComplexAugmentContainerBuilder.class);
+ // 2
+ // Noop reader(no real attributes)
+ private Reader<ContainerWithList, ContainerWithListBuilder> containerWithListReader =
+ mockReader(Ids.CONTAINER_WITH_LIST_ID, HoneycombReadInfraTest::noopRead, ContainerWithListBuilder.class);
+ // 2.1
+ private ListReader<ListInContainer, ListInContainerKey, ListInContainerBuilder> listInContainerReader =
+ mockListReader(Ids.LIST_IN_CONTAINER_ID, this::readListInContainer, this::getListInContainerIds,
+ ListInContainerBuilder.class);
+ // 2.1.1
+ private Reader<ContainerInList, ContainerInListBuilder> containerInListReader =
+ mockReader(Ids.CONTAINER_IN_LIST_ID, this::readContainerInList, ContainerInListBuilder.class);
+ // 2.1.1.1
+ private ListReader<NestedList, NestedListKey, NestedListBuilder> nestedListReader =
+ mockListReader(Ids.NESTED_LIST_ID, this::readNestedList, this::getNestedListIds,
+ NestedListBuilder.class);
+
+ @Override
+ void postSetup() {
+ initReaderRegistry();
+ }
+
+ private void initReaderRegistry() {
+ registry = new CompositeReaderRegistryBuilder()
+ .add(containerWithListReader) // 2
+ .addBefore(simpleContainerReader, Ids.CONTAINER_WITH_LIST_ID) // 1
+ .add(simpleAugmentReader) // 1.1
+ .addAfter(complexAugmentReader, Ids.SIMPLE_AUGMENT_ID) // 1.2
+ .add(complexAugmentContainerReader) // 1.2.1
+ .add(listInContainerReader) // 2.1
+ .add(containerInListReader) // 2.1.1
+ .addBefore(nestedListReader, Ids.SIMPLE_AUGMENT_ID) // 2.1.1.1 - Before relationship should be ignored
+ .build();
+ }
+
+ private Reader<?, ?>[] getOrderedReaders() {
+ return new Reader<?, ?>[]{simpleContainerReader, // 1
+ simpleAugmentReader, // 1.1
+ complexAugmentReader, // 1.2
+ complexAugmentContainerReader, // 1.2.1
+ containerWithListReader, // 2
+ listInContainerReader, // 2.1
+ containerInListReader, // 2.1.1
+ nestedListReader}; // 2.1.1.1
+ }
+
+ @Test
+ public void testReadAll() throws Exception {
+ final ReadableDataTreeDelegator readableDataTreeDelegator =
+ new ReadableDataTreeDelegator(serializer, schemaContext, registry, contextBroker);
+ final CheckedFuture<Optional<NormalizedNode<?, ?>>, org.opendaylight.controller.md.sal.common.api.data.ReadFailedException>
+ read = readableDataTreeDelegator.read(YangInstanceIdentifier.EMPTY);
+
+ final Multimap<InstanceIdentifier<? extends DataObject>, ? extends DataObject> readAll =
+ toBinding(read.checkedGet().get());
+ assertThat(readAll.size(), is(2));
+ assertTrue(readAll.containsKey(Ids.CONTAINER_WITH_LIST_ID));
+ assertEquals(readContainerWithList(), readAll.get(Ids.CONTAINER_WITH_LIST_ID).stream().findFirst().get());
+ assertTrue(readAll.containsKey(Ids.SIMPLE_CONTAINER_ID));
+ assertEquals(readSimpleContainer(), readAll.get(Ids.SIMPLE_CONTAINER_ID).stream().findFirst().get());
+
+ final Reader<?, ?>[] ordered = getOrderedReaders();
+ final InOrder inOrder = inOrder(ordered);
+
+ final List<ListInContainerKey> listInContainerKeys = getListInContainerIds(Ids.LIST_IN_CONTAINER_ID, ctx);
+
+ verifyRootReader(inOrder, simpleContainerReader, Ids.SIMPLE_CONTAINER_ID, SimpleContainerBuilder.class);
+ verifyLeafChildReader(inOrder, simpleAugmentReader, Ids.SIMPLE_AUGMENT_ID);
+ verifyCompositeChildReader(inOrder, complexAugmentReader, ComplexAugmentBuilder.class, Ids.COMPLEX_AUGMENT_ID);
+ verifyLeafChildReader(inOrder, complexAugmentContainerReader, Ids.COMPLEX_AUGMENT_CONTAINER_ID);
+ verifyRootReader(inOrder, containerWithListReader, Ids.CONTAINER_WITH_LIST_ID, ContainerWithListBuilder.class);
+ verifyCompositeListReader(inOrder, listInContainerReader, Ids.LIST_IN_CONTAINER_ID,
+ listInContainerKeys, ListInContainerBuilder.class);
+
+ for (ListInContainerKey k : listInContainerKeys) {
+ final InstanceIdentifier<ContainerInList> id =
+ Ids.CONTAINER_WITH_LIST_ID.child(ListInContainer.class, k).child(ContainerInList.class);
+ verifyCompositeChildReader(inOrder, containerInListReader, ContainerInListBuilder.class, id);
+ final InstanceIdentifier<NestedList> nestedId = id.child(NestedList.class);
+ verifyLeafListReader(inOrder, nestedListReader, nestedId);
+ }
+
+ for (Reader<?, ?> reader : ordered) {
+ verifyNoMoreReadInteractions(reader);
+ }
+ }
+
+ private <D extends DataObject, B extends Builder<D>> void verifyNoMoreReadInteractions(final Reader<D, B> reader) {
+ verify(reader, atLeastOnce()).getManagedDataObjectType();
+ verifyNoMoreInteractions(reader);
+ }
+
+ private <D extends DataObject, B extends Builder<D>> void verifyCompositeChildReader(final InOrder inOrder,
+ final Reader<D, B> reader,
+ final Class<B> builderCls,
+ final InstanceIdentifier<D> id)
+ throws ReadFailedException {
+ verifyRootReader(inOrder, reader, id, builderCls);
+ verify(reader, atLeastOnce()).merge(any(Builder.class), any(id.getTargetType()));
+ }
+
+ private <D extends DataObject & Identifiable<K>, K extends Identifier<D>, B extends Builder<D>> void verifyCompositeListReader(
+ final InOrder inOrder,
+ final ListReader<D, K, B> reader,
+ final InstanceIdentifier<D> id,
+ final List<K> keys,
+ final Class<B> builderCls)
+ throws ReadFailedException {
+
+ // Id has to be wildcarded, since it was created using InstanceIdentifier.child() method
+ inOrder.verify(reader).getAllIds(eq(RWUtils.makeIidLastWildcarded(id)), any(ReadContext.class));
+ keys.stream()
+ .map(k -> RWUtils.replaceLastInId(id, RWUtils.getCurrentIdItem(id, k)))
+ .forEach(keyedId -> {
+ try {
+ verify(reader).getBuilder(keyedId);
+ verify(reader).readCurrentAttributes(eq(keyedId), any(builderCls), any(ReadContext.class));
+ } catch (ReadFailedException e) { throw new RuntimeException(e); }
+ });
+ verify(reader, atLeastOnce()).merge(any(Builder.class), anyListOf(id.getTargetType()));
+ }
+
+ private <D extends DataObject & Identifiable<K>, K extends Identifier<D>, B extends Builder<D>> void verifyLeafListReader(
+ final InOrder inOrder,
+ final ListReader<D, K, B> reader,
+ final InstanceIdentifier<D> id)
+ throws ReadFailedException {
+
+ // Id has to be wildcarded, since it was created using InstanceIdentifier.child() method
+ inOrder.verify(reader).readList(eq(RWUtils.makeIidLastWildcarded(id)), any(ReadContext.class));
+ verify(reader, atLeastOnce()).merge(any(Builder.class), anyListOf(id.getTargetType()));
+ }
+
+ private <D extends DataObject, B extends Builder<D>> void verifyRootReader(final InOrder inOrder,
+ final Reader<D, B> reader,
+ final InstanceIdentifier<D> id,
+ final Class<B> builderCls)
+ throws ReadFailedException {
+ inOrder.verify(reader).readCurrentAttributes(eq(id), any(builderCls), any(ReadContext.class));
+ verify(reader).getBuilder(id);
+ }
+
+
+ private <D extends DataObject, B extends Builder<D>> void verifyLeafChildReader(final InOrder inOrder,
+ final Reader<D, B> reader,
+ final InstanceIdentifier<D>... id)
+ throws ReadFailedException {
+ for (InstanceIdentifier<D> singleId : id) {
+ inOrder.verify(reader).read(eq(singleId), any(ReadContext.class));
+ verify(reader, atLeastOnce()).merge(any(Builder.class), any(singleId.getTargetType()));
+ }
+ }
+
+ static <D extends DataObject, B extends Builder<D>> Reader<D, B> mockReader(InstanceIdentifier<D> id,
+ CurrentAttributesReader<D, B> currentAttributesReader,
+ Class<B> builderClass) {
+ final ReflexiveReader<D, B> reflex = new ReflexiveReader<D, B>(id, builderClass) {
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<D> id,
+ @Nonnull final B builder,
+ @Nonnull final ReadContext ctx)
+ throws ReadFailedException {
+ currentAttributesReader.readCurrentAttributes(id, builder, ctx);
+ }
+ };
+
+ // Simple spy on top of this reflexive reader cannot be used, spy also checks protected methods for invocation
+ // but those cannot be verified by mockito
+ final Reader<D, B> mock = mock(Reader.class);
+ try {
+ doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock).read(any(InstanceIdentifier.class), any(ReadContext.class));
+ doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock)
+ .readCurrentAttributes(any(InstanceIdentifier.class), any(builderClass), any(ReadContext.class));
+ doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock).merge(any(Builder.class), any(id.getTargetType()));
+ doReturn(id).when(mock).getManagedDataObjectType();
+ doReturn(builderClass.newInstance()).when(mock).getBuilder(any(InstanceIdentifier.class));
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ return mock;
+ }
+
+ static <D extends DataObject & Identifiable<K>, K extends Identifier<D>, B extends Builder<D>> ListReader<D, K, B> mockListReader(
+ InstanceIdentifier<D> id,
+ CurrentAttributesReader<D, B> currentAttributesReader,
+ ListKeysReader<D, K> listKeysReader,
+ Class<B> builderClass) {
+
+ ListReader<D, K, B> reflex = new GenericListReader<>(id,
+ new ReflexiveListReaderCustomizer<D, K, B>(id.getTargetType(), builderClass) {
+
+ @Nonnull
+ @Override
+ public List<K> getAllIds(@Nonnull final InstanceIdentifier<D> id, @Nonnull final ReadContext context)
+ throws ReadFailedException {
+ return listKeysReader.getAllIds(id, context);
+ }
+
+ @Override
+ public void readCurrentAttributes(final InstanceIdentifier<D> id, final B builder,
+ final ReadContext context)
+ throws ReadFailedException {
+ currentAttributesReader.readCurrentAttributes(id, builder, context);
+ }
+ });
+
+ final ListReader<D, K, B> mock = mock(ListReader.class /*, withSettings().verboseLogging()*/);
+ try {
+ // not using eq(id) instead using any(InstanceIdentifier.class) due to InstanceIdentifier.equals weird behavior
+ // with wildcarded instance identifiers for lists
+ doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock).read(any(InstanceIdentifier.class), any(ReadContext.class));
+ doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock)
+ .readCurrentAttributes(any(InstanceIdentifier.class), any(builderClass), any(ReadContext.class));
+ doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock).merge(any(Builder.class), any(id.getTargetType()));
+ doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock).merge(any(Builder.class), anyListOf(id.getTargetType()));
+ doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock).getAllIds(any(InstanceIdentifier.class), any(ReadContext.class));
+ doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock).readList(any(InstanceIdentifier.class), any(ReadContext.class));
+ doReturn(id).when(mock).getManagedDataObjectType();
+ doReturn(builderClass.newInstance()).when(mock).getBuilder(any(InstanceIdentifier.class));
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ return mock;
+ }
+
+ private static <D extends DataObject, B extends Builder<D>> Object reflexiveAnswer(final Reader<D, B> instance,
+ final InvocationOnMock i) {
+ try {
+ return i.getMethod().invoke(instance, i.getArguments());
+ } catch (IllegalAccessException | InvocationTargetException e) {
+ throw new MockitoConfigurationException("Unable to invoke stubbed method invocation: " + i + " on " + instance);
+ }
+ }
+
+ @FunctionalInterface
+ interface CurrentAttributesReader<D extends DataObject, B extends Builder<D>> {
+ void readCurrentAttributes(@Nonnull final InstanceIdentifier<D> id,
+ @Nonnull final B builder,
+ @Nonnull final ReadContext ctx);
+ }
+
+ @FunctionalInterface
+ interface ListKeysReader<D extends DataObject & Identifiable<K>, K extends Identifier<D>> {
+ List<K> getAllIds(@Nonnull final InstanceIdentifier<D> id,
+ @Nonnull final ReadContext ctx);
+ }
+
+
+ private void readSimpleContainer(final InstanceIdentifier<SimpleContainer> id,
+ final SimpleContainerBuilder b,
+ final ReadContext readContext) {
+ b.setSimpleContainerName("simple");
+ }
+
+ private SimpleContainer readSimpleContainer() {
+ final SimpleContainerBuilder b = new SimpleContainerBuilder();
+ readSimpleContainer(Ids.SIMPLE_CONTAINER_ID, b, ctx);
+ b.addAugmentation(SimpleAugment.class, readSimpleAugment());
+ b.addAugmentation(ComplexAugment.class,
+ new ComplexAugmentBuilder().setComplexAugmentContainer(readComplexAugmentContainer()).build());
+ return b.build();
+ }
+
+ private void readSimpleAugment(final InstanceIdentifier<SimpleAugment> id,
+ final SimpleAugmentBuilder b,
+ final ReadContext readContext) {
+ b.setSimpleAugmentLeaf("simple augment");
+ }
+
+ private SimpleAugment readSimpleAugment() {
+ final SimpleAugmentBuilder b = new SimpleAugmentBuilder();
+ readSimpleAugment(Ids.SIMPLE_AUGMENT_ID, b, ctx);
+ return b.build();
+ }
+
+ private void readComplexAugmentContainer(final InstanceIdentifier<ComplexAugmentContainer> id,
+ final ComplexAugmentContainerBuilder b,
+ final ReadContext readContext) {
+ b.setSomeLeaf("nested container in augment");
+ }
+
+ private ComplexAugmentContainer readComplexAugmentContainer() {
+ final ComplexAugmentContainerBuilder b = new ComplexAugmentContainerBuilder();
+ readComplexAugmentContainer(Ids.COMPLEX_AUGMENT_CONTAINER_ID, b, ctx);
+ return b.build();
+ }
+
+ private ContainerWithList readContainerWithList() {
+ final ContainerWithListBuilder b = new ContainerWithListBuilder();
+ b.setListInContainer(readListInContainer());
+ return b.build();
+ }
+
+ private List<ListInContainerKey> getListInContainerIds(final InstanceIdentifier<ListInContainer> id,
+ final ReadContext readContext) {
+ return Lists.newArrayList(1L, 2L)
+ .stream()
+ .map(ListInContainerKey::new)
+ .collect(Collectors.toList());
+ }
+
+ private List<NestedListKey> getNestedListIds(final InstanceIdentifier<NestedList> id,
+ final ReadContext readContext) {
+ return Lists.newArrayList("one", "two")
+ .stream()
+ .map(NestedListKey::new)
+ .collect(Collectors.toList());
+ }
+
+ private void readListInContainer(final InstanceIdentifier<ListInContainer> id,
+ final ListInContainerBuilder b,
+ final ReadContext readContext) {
+ final ListInContainerKey key = id.firstKeyOf(ListInContainer.class);
+ b.setId(key.getId());
+ final ContainerInListBuilder cilBuilder = new ContainerInListBuilder();
+ readContainerInList(id.child(ContainerInList.class), cilBuilder, readContext);
+ b.setContainerInList(cilBuilder.build());
+ }
+
+ private void readNestedList(final InstanceIdentifier<NestedList> id,
+ final NestedListBuilder b,
+ final ReadContext readContext) {
+ final NestedListKey key = id.firstKeyOf(NestedList.class);
+ b.setNestedId(key.getNestedId());
+ b.setNestedName(key.getNestedId() + "name");
+ }
+
+ private void readContainerInList(final InstanceIdentifier<ContainerInList> id,
+ final ContainerInListBuilder b,
+ final ReadContext readContext) {
+ b.setName(id.firstKeyOf(ListInContainer.class).getId().toString());
+ b.setNestedList(getNestedListIds(Ids.NESTED_LIST_ID, ctx).stream()
+ .map(key -> id.child(NestedList.class, key))
+ .map(nestedId -> {
+ final NestedListBuilder nestedB = new NestedListBuilder();
+ readNestedList(nestedId, nestedB, readContext);
+ return nestedB.build();
+ })
+ .collect(Collectors.toList()));
+ }
+
+ private List<ListInContainer> readListInContainer() {
+ return getListInContainerIds(Ids.LIST_IN_CONTAINER_ID, ctx).stream()
+ .map(key -> Ids.CONTAINER_WITH_LIST_ID.child(ListInContainer.class, key))
+ .map(id -> {
+ final ListInContainerBuilder b = new ListInContainerBuilder();
+ readListInContainer(id, b, ctx);
+ return b.build();
+ }).collect(Collectors.toList());
+ }
+
+ static <D extends DataObject, B extends Builder<D>> void noopRead(final InstanceIdentifier<D> id, final B b,
+ final ReadContext readContext) {
+ // NOOP
+ }
+
+}
diff --git a/infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombSubtreeReadInfraTest.java b/infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombSubtreeReadInfraTest.java
new file mode 100644
index 0000000..8faeb84
--- /dev/null
+++ b/infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombSubtreeReadInfraTest.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.data.impl;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.CheckedFuture;
+import io.fd.honeycomb.v3po.translate.impl.read.GenericListReader;
+import io.fd.honeycomb.v3po.translate.read.ListReader;
+import io.fd.honeycomb.v3po.translate.read.ReadContext;
+import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
+import io.fd.honeycomb.v3po.translate.read.Reader;
+import io.fd.honeycomb.v3po.translate.read.registry.ReaderRegistry;
+import io.fd.honeycomb.v3po.translate.util.read.ReflexiveListReaderCustomizer;
+import io.fd.honeycomb.v3po.translate.util.read.registry.CompositeReaderRegistryBuilder;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainerBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainerKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInListBuilder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public class HoneycombSubtreeReadInfraTest extends AbstractInfraTest {
+
+ @Mock
+ private ReadContext ctx;
+ private ReaderRegistry registry;
+
+ private Reader<ContainerWithList, ContainerWithListBuilder> containerWithListReader =
+ HoneycombReadInfraTest.mockReader(Ids.CONTAINER_WITH_LIST_ID, this::readSubtree, ContainerWithListBuilder.class);
+
+ private ListReader<ListInContainer, ListInContainerKey, ListInContainerBuilder> listInContainerReader =
+ new GenericListReader<>(Ids.LIST_IN_CONTAINER_ID,
+ new ReflexiveListReaderCustomizer<ListInContainer, ListInContainerKey, ListInContainerBuilder>(Ids.LIST_IN_CONTAINER_ID.getTargetType(), ListInContainerBuilder.class) {
+
+ @Nonnull
+ @Override
+ public List<ListInContainerKey> getAllIds(@Nonnull final InstanceIdentifier<ListInContainer> id,
+ @Nonnull final ReadContext context)
+ throws ReadFailedException {
+ // FIXME this is the only way of extending subtree reader via its list child
+ // Reflexive list reader has to be used in place of the list(managed by subtree reader perent)
+ // to enable further children readers. However, it will not work out of the box, because
+ // reflexive list reader has no way to tell what are the IDs to correctly invoke its children.
+ // Only way is to override the getAllIds method in reflexive reader and return the same list
+ // as parent used (this can be done using cache or repeated dump call)
+ return Lists.newArrayList(new ListInContainerKey(1L), new ListInContainerKey(2L));
+ }
+
+ @Override
+ public void readCurrentAttributes(final InstanceIdentifier<ListInContainer> id,
+ final ListInContainerBuilder builder,
+ final ReadContext context) throws ReadFailedException {
+ super.readCurrentAttributes(id, builder, context);
+ builder.setKey(id.firstKeyOf(ListInContainer.class));
+ }
+ });
+
+ private Reader<ContainerInList, ContainerInListBuilder> containerInListReader =
+ HoneycombReadInfraTest.mockReader(Ids.CONTAINER_IN_LIST_ID, this::readContainerInList, ContainerInListBuilder.class);
+
+ // TODO Test subtree readers especially composite structure where readers are under subtree reader
+
+ @Override
+ void postSetup() {
+ initReaderRegistry();
+ }
+
+ private void initReaderRegistry() {
+ registry = new CompositeReaderRegistryBuilder()
+ // Subtree reader handling its child list
+ .subtreeAdd(Sets.newHashSet(Ids.LIST_IN_CONTAINER_ID), containerWithListReader)
+ // Reflexive
+ .add(listInContainerReader)
+ .add(containerInListReader)
+ .build();
+ }
+
+ @Test
+ public void testReadAll() throws Exception {
+ final ReadableDataTreeDelegator readableDataTreeDelegator =
+ new ReadableDataTreeDelegator(serializer, schemaContext, registry, contextBroker);
+ final CheckedFuture<Optional<NormalizedNode<?, ?>>, org.opendaylight.controller.md.sal.common.api.data.ReadFailedException>
+ read = readableDataTreeDelegator.read(YangInstanceIdentifier.EMPTY);
+
+ final Multimap<InstanceIdentifier<? extends DataObject>, ? extends DataObject> readAll =
+ toBinding(read.checkedGet().get());
+ assertThat(readAll.size(), is(1));
+ assertEquals(readEntireSubtree(), readAll.get(Ids.CONTAINER_WITH_LIST_ID).stream().findFirst().get());
+ }
+
+ private void readSubtree(final InstanceIdentifier<ContainerWithList> id,
+ final ContainerWithListBuilder b,
+ final ReadContext readContext) {
+ b.setListInContainer(Lists.newArrayList(1L, 2L).stream()
+ .map(l -> new ListInContainerBuilder().setId(l).build())
+ .collect(Collectors.toList()));
+ }
+
+ private ContainerWithList readEntireSubtree() {
+ final ContainerWithListBuilder b = new ContainerWithListBuilder();
+ b.setListInContainer(Lists.newArrayList(1L, 2L).stream()
+ .map(l -> {
+ final ContainerInListBuilder containerInListBuilder = new ContainerInListBuilder();
+ readContainerInList(
+ Ids.CONTAINER_WITH_LIST_ID.child(ListInContainer.class, new ListInContainerKey(l)).child(ContainerInList.class),
+ containerInListBuilder,
+ ctx);
+ return new ListInContainerBuilder().setId(l).setContainerInList(containerInListBuilder.build()).build();
+ })
+ .collect(Collectors.toList()));
+ return b.build();
+ }
+
+ private void readContainerInList(final InstanceIdentifier<ContainerInList> id,
+ final ContainerInListBuilder b,
+ final ReadContext readContext) {
+ b.setName(id.firstKeyOf(ListInContainer.class).getId().toString());
+ }
+}
diff --git a/infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombWriteInfraTest.java b/infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombWriteInfraTest.java
new file mode 100644
index 0000000..b3a06ec
--- /dev/null
+++ b/infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombWriteInfraTest.java
@@ -0,0 +1,521 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.data.impl;
+
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import io.fd.honeycomb.v3po.data.DataModification;
+import io.fd.honeycomb.v3po.translate.util.write.registry.FlatWriterRegistryBuilder;
+import io.fd.honeycomb.v3po.translate.write.WriteContext;
+import io.fd.honeycomb.v3po.translate.write.Writer;
+import io.fd.honeycomb.v3po.translate.write.registry.WriterRegistry;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import org.junit.Test;
+import org.mockito.InOrder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ComplexAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ComplexAugmentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithChoice;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithChoiceBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleAugmentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleContainer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleContainerBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.choice.Choice;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.choice.choice.c3.C3;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.choice.choice.c3.C3Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainerBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainerKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.container.in.list.NestedList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.container.in.list.NestedListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.container.in.list.NestedListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.simple.container.ComplexAugmentContainer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.simple.container.ComplexAugmentContainerBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.some.attributes.ContainerFromGrouping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.some.attributes.ContainerFromGroupingBuilder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.TipProducingDataTree;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType;
+import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory;
+
+/**
+ * Testing honeycomb writes from data tree up to mocked writers.
+ */
+public class HoneycombWriteInfraTest extends AbstractInfraTest {
+
+ private TipProducingDataTree dataTree;
+ private WriterRegistry writerRegistry;
+
+ Writer<SimpleContainer> simpleContainerWriter = mockWriter(Ids.SIMPLE_CONTAINER_ID);
+ Writer<ComplexAugment> complexAugmentWriter = mockWriter(Ids.COMPLEX_AUGMENT_ID);
+ Writer<ComplexAugmentContainer> complexAugmentContainerWriter = mockWriter(Ids.COMPLEX_AUGMENT_CONTAINER_ID);
+ Writer<SimpleAugment> simpleAugmentWriter = mockWriter(Ids.SIMPLE_AUGMENT_ID);
+
+ Writer<ContainerWithList> containerWithListWriter = mockWriter(Ids.CONTAINER_WITH_LIST_ID);
+ Writer<ListInContainer> listInContainerWriter = mockWriter(Ids.LIST_IN_CONTAINER_ID);
+ Writer<ContainerInList> containerInListWriter = mockWriter(Ids.CONTAINER_IN_LIST_ID);
+ Writer<NestedList> nestedListWriter = mockWriter(Ids.NESTED_LIST_ID);
+
+ Writer<ContainerWithChoice> containerWithChoiceWriter = mockWriter(Ids.CONTAINER_WITH_CHOICE_ID);
+ Writer<ContainerFromGrouping> containerFromGroupingWriter = mockWriter(Ids.CONTAINER_FROM_GROUPING_ID);
+ Writer<C3> c3Writer = mockWriter(Ids.C3_ID);
+
+
+ private static <D extends DataObject> Writer<D> mockWriter(final InstanceIdentifier<D> id) {
+ final Writer<D> mock = (Writer<D>) mock(Writer.class);
+ when(mock.getManagedDataObjectType()).thenReturn(id);
+ return mock;
+ }
+
+ @Override
+ void postSetup() {
+ initDataTree();
+ initWriterRegistry();
+ }
+
+ private void initDataTree() {
+ dataTree = InMemoryDataTreeFactory.getInstance().create(TreeType.CONFIGURATION);
+ dataTree.setSchemaContext(schemaContext);
+ }
+
+ private void initWriterRegistry() {
+ writerRegistry = new FlatWriterRegistryBuilder()
+ .add(complexAugmentWriter) // unordered
+ .add(nestedListWriter) // 6
+ .addAfter(listInContainerWriter, Ids.NESTED_LIST_ID) // 7
+ .addAfter(containerInListWriter, Ids.LIST_IN_CONTAINER_ID) // 8
+ .addAfter(containerWithListWriter, Ids.CONTAINER_IN_LIST_ID) // 9
+ .addBefore(containerFromGroupingWriter, Ids.NESTED_LIST_ID) // 5
+ .addBefore(containerWithChoiceWriter, Ids.CONTAINER_FROM_GROUPING_ID) // 4
+ .addBefore(simpleContainerWriter, Ids.CONTAINER_WITH_CHOICE_ID) // 3
+ .addBefore(c3Writer, Ids.SIMPLE_CONTAINER_ID) // 2
+ .addBefore(simpleAugmentWriter, Ids.SIMPLE_CONTAINER_ID) // 2
+ .addBefore(complexAugmentContainerWriter, Sets.newHashSet(Ids.C3_ID, Ids.SIMPLE_AUGMENT_ID)) // 1
+ .build();
+ }
+
+ @Test
+ public void testWriteEmptyNonPresenceContainer() throws Exception {
+ final ModifiableDataTreeDelegator modifiableDataTreeDelegator =
+ new ModifiableDataTreeDelegator(serializer, dataTree, writerRegistry, contextBroker);
+
+ final DataModification dataModification = modifiableDataTreeDelegator.newModification();
+ final SimpleContainer data = new SimpleContainerBuilder()
+ .build();
+
+ final Map.Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> normalizedNode =
+ serializer.toNormalizedNode(Ids.SIMPLE_CONTAINER_ID, data);
+ dataModification.write(normalizedNode.getKey(), normalizedNode.getValue());
+
+ dataModification.commit();
+
+ verify(simpleContainerWriter).getManagedDataObjectType();
+ verifyNoMoreInteractions(simpleContainerWriter);
+ }
+
+ @Test
+ public void testWriteEverything() throws Exception {
+ final ModifiableDataTreeDelegator modifiableDataTreeDelegator =
+ new ModifiableDataTreeDelegator(serializer, dataTree, writerRegistry, contextBroker);
+
+ final DataModification dataModification = modifiableDataTreeDelegator.newModification();
+ // Now write everything we can
+ writeSimpleContainer(dataModification);
+ writeContainerWithChoice(dataModification);
+ writeContainerWithList(dataModification);
+ dataModification.commit();
+
+ final Writer<?>[] orderedWriters = getOrderedWriters();
+ final InOrder inOrder = inOrder(orderedWriters);
+ verifyOrderedWrites(orderedWriters, inOrder);
+ }
+
+ private void verifyOrderedWrites(final Writer<?>[] orderedWriters, final InOrder inOrder)
+ throws io.fd.honeycomb.v3po.translate.write.WriteFailedException {
+ // TODO Modifications are not produced for nodes that do not contain any actual leaves (except when choice is a child) do we need those triggers ?
+ // Unordered
+ // verify(complexAugmentWriter).update(eq(COMPLEX_AUGMENT_ID), eq(null), eq(getComplexAugment()), any(WriteContext.class));
+ // 1
+ inOrder.verify(complexAugmentContainerWriter)
+ .update(eq(Ids.COMPLEX_AUGMENT_CONTAINER_ID), eq(null), eq(getComplexAugmentContainer()), any(WriteContext.class));
+ // 2
+ inOrder.verify(c3Writer)
+ .update(eq(Ids.C3_ID), eq(null), eq(getC3()), any(WriteContext.class));
+ // 2
+ verify(simpleAugmentWriter)
+ .update(eq(Ids.SIMPLE_AUGMENT_ID), eq(null), eq(getSimpleAugment()), any(WriteContext.class));
+ // 3
+ inOrder.verify(simpleContainerWriter)
+ .update(eq(Ids.SIMPLE_CONTAINER_ID), eq(null), eq(getSimpleContainer()), any(WriteContext.class));
+ // 4
+ inOrder.verify(containerWithChoiceWriter)
+ .update(eq(Ids.CONTAINER_WITH_CHOICE_ID), eq(null), eq(getContainerWithChoiceWithComplexCase()), any(WriteContext.class));
+ // 5
+ inOrder.verify(containerFromGroupingWriter)
+ .update(eq(Ids.CONTAINER_FROM_GROUPING_ID), eq(null), eq(getContainerFromGrouping()), any(WriteContext.class));
+
+ final KeyedInstanceIdentifier<ListInContainer, ListInContainerKey> keyedListInContainer1 =
+ Ids.CONTAINER_WITH_LIST_ID.child(ListInContainer.class, new ListInContainerKey((long) 1));
+ final KeyedInstanceIdentifier<NestedList, NestedListKey> keyedNestedList1 =
+ keyedListInContainer1.child(ContainerInList.class).child(NestedList.class, new NestedListKey("1"));
+ final KeyedInstanceIdentifier<ListInContainer, ListInContainerKey> keyedListInContainer2 =
+ Ids.CONTAINER_WITH_LIST_ID.child(ListInContainer.class, new ListInContainerKey((long) 2));
+ final KeyedInstanceIdentifier<NestedList, NestedListKey> keyedNestedList2 =
+ keyedListInContainer2.child(ContainerInList.class).child(NestedList.class, new NestedListKey("2"));
+
+ // 6 - two items
+ inOrder.verify(nestedListWriter)
+ .update(eq(keyedNestedList1), eq(null), eq(getSingleNestedList("1")), any(WriteContext.class));
+ verify(nestedListWriter)
+ .update(eq(keyedNestedList2), eq(null), eq(getSingleNestedList("2")), any(WriteContext.class));
+
+ // 7 - two items
+ inOrder.verify(listInContainerWriter)
+ .update(eq(keyedListInContainer1), eq(null), eq(getSingleListInContainer((long)1)), any(WriteContext.class));
+ verify(listInContainerWriter)
+ .update(eq(keyedListInContainer2), eq(null), eq(getSingleListInContainer((long)2)), any(WriteContext.class));
+
+ // 8
+ inOrder.verify(containerInListWriter)
+ .update(eq(keyedListInContainer1.child(ContainerInList.class)), eq(null), eq(getContainerInList("1")), any(WriteContext.class));
+ verify(containerInListWriter)
+ .update(eq(keyedListInContainer2.child(ContainerInList.class)), eq(null), eq(getContainerInList("2")), any(WriteContext.class));
+
+ // 9 - Ignored because the container has no leaves, only complex child nodes
+ // inOrder.verify(containerWithListWriter)
+ // .update(eq(CONTAINER_WITH_LIST_ID), eq(null), eq(getContainerWithList()), any(WriteContext.class));
+
+ for (Writer<?> orderedWriter : orderedWriters) {
+ verify(orderedWriter).getManagedDataObjectType();
+ verifyNoMoreInteractions(orderedWriter);
+ }
+ }
+
+ private Writer<?>[] getOrderedWriters() {
+ return new Writer<?>[]{complexAugmentWriter, // Unordered
+ complexAugmentContainerWriter, // 1
+ c3Writer, // 2
+ simpleAugmentWriter, // 2
+ simpleContainerWriter, // 3
+ containerWithChoiceWriter, // 4
+ containerFromGroupingWriter, // 5
+ nestedListWriter, // 6
+ listInContainerWriter, // 7
+ containerInListWriter, // 8
+ containerWithListWriter};
+ }
+
+ @Test
+ public void testDeletes() throws Exception {
+ final ModifiableDataTreeDelegator modifiableDataTreeDelegator =
+ new ModifiableDataTreeDelegator(serializer, dataTree, writerRegistry, contextBroker);
+
+ DataModification dataModification = modifiableDataTreeDelegator.newModification();
+ // Now write everything we can
+ writeSimpleContainer(dataModification);
+ writeContainerWithChoice(dataModification);
+ writeContainerWithList(dataModification);
+ dataModification.commit();
+ // Verify writes to be able to verifyNoMore interactions at the end
+ verifyOrderedWrites(getOrderedWriters(), inOrder(getOrderedWriters()));
+
+ dataModification = modifiableDataTreeDelegator.newModification();
+ deleteSimpleContainer(dataModification);
+ deleteContainerWithChoice(dataModification);
+ deleteContainerWithList(dataModification);
+ dataModification.commit();
+
+ final Writer<?>[] orderedWriters = getOrderedWriters();
+ Collections.reverse(Arrays.asList(orderedWriters));
+ final InOrder inOrder = inOrder(orderedWriters);
+
+ final KeyedInstanceIdentifier<ListInContainer, ListInContainerKey> keyedListInContainer1 =
+ Ids.CONTAINER_WITH_LIST_ID.child(ListInContainer.class, new ListInContainerKey((long) 1));
+ final KeyedInstanceIdentifier<NestedList, NestedListKey> keyedNestedList1 =
+ keyedListInContainer1.child(ContainerInList.class).child(NestedList.class, new NestedListKey("1"));
+ final KeyedInstanceIdentifier<ListInContainer, ListInContainerKey> keyedListInContainer2 =
+ Ids.CONTAINER_WITH_LIST_ID.child(ListInContainer.class, new ListInContainerKey((long) 2));
+ final KeyedInstanceIdentifier<NestedList, NestedListKey> keyedNestedList2 =
+ keyedListInContainer2.child(ContainerInList.class).child(NestedList.class, new NestedListKey("2"));
+
+ // Deletes are handled in reverse order
+ // 1
+ inOrder.verify(containerInListWriter)
+ .update(eq(keyedListInContainer1.child(ContainerInList.class)), eq(getContainerInList("1")), eq(null), any(WriteContext.class));
+ verify(containerInListWriter)
+ .update(eq(keyedListInContainer2.child(ContainerInList.class)), eq(getContainerInList("2")), eq(null), any(WriteContext.class));
+
+ // 2
+ inOrder.verify(listInContainerWriter)
+ .update(eq(keyedListInContainer1), eq(getSingleListInContainer((long)1)), eq(null), any(WriteContext.class));
+ verify(listInContainerWriter)
+ .update(eq(keyedListInContainer2), eq(getSingleListInContainer((long)2)), eq(null), any(WriteContext.class));
+
+ // 3
+ inOrder.verify(nestedListWriter)
+ .update(eq(keyedNestedList1), eq(getSingleNestedList("1")), eq(null), any(WriteContext.class));
+ verify(nestedListWriter)
+ .update(eq(keyedNestedList2), eq(getSingleNestedList("2")), eq(null), any(WriteContext.class));
+ // 4
+ inOrder.verify(containerFromGroupingWriter)
+ .update(eq(Ids.CONTAINER_FROM_GROUPING_ID), eq(getContainerFromGrouping()), eq(null), any(WriteContext.class));
+ // 5
+ inOrder.verify(containerWithChoiceWriter)
+ .update(eq(Ids.CONTAINER_WITH_CHOICE_ID), eq(getContainerWithChoiceWithComplexCase()), eq(null), any(WriteContext.class));
+ // 6
+ inOrder.verify(simpleContainerWriter)
+ .update(eq(Ids.SIMPLE_CONTAINER_ID), eq(getSimpleContainer()), eq(null), any(WriteContext.class));
+ // 7
+ verify(simpleAugmentWriter)
+ .update(eq(Ids.SIMPLE_AUGMENT_ID), eq(getSimpleAugment()), eq(null), any(WriteContext.class));
+ // 8
+ inOrder.verify(c3Writer)
+ .update(eq(Ids.C3_ID), eq(getC3()), eq(null), any(WriteContext.class));
+ // 9
+ inOrder.verify(complexAugmentContainerWriter)
+ .update(eq(Ids.COMPLEX_AUGMENT_CONTAINER_ID), eq(getComplexAugmentContainer()), eq(null), any(WriteContext.class));
+
+ for (Writer<?> orderedWriter : orderedWriters) {
+ verify(orderedWriter).getManagedDataObjectType();
+ verifyNoMoreInteractions(orderedWriter);
+ }
+ }
+
+ private void writeContainerWithList(final DataModification dataModification) {
+ final Map.Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> normalizedNode =
+ serializer.toNormalizedNode(Ids.CONTAINER_WITH_LIST_ID, getContainerWithList());
+ dataModification.write(normalizedNode.getKey(), normalizedNode.getValue());
+ }
+
+ private void deleteContainerWithList(final DataModification dataModification) {
+ dataModification.delete(serializer.toYangInstanceIdentifier(Ids.CONTAINER_WITH_LIST_ID));
+ }
+
+ private ContainerWithList getContainerWithList() {
+ return new ContainerWithListBuilder()
+ .setListInContainer(getListInContainer((long)1, (long)2))
+ .build();
+ }
+
+ private List<ListInContainer> getListInContainer(final Long... keys) {
+ final ArrayList<ListInContainer> objects = Lists.newArrayList();
+ for (Long key : keys) {
+ objects.add(getSingleListInContainer(key));
+ }
+ return objects;
+ }
+
+ private ListInContainer getSingleListInContainer(final Long key) {
+ return new ListInContainerBuilder()
+ .setId(key)
+ .setContainerInList(getContainerInList(Long.toString(key)))
+ .build();
+ }
+
+ private ContainerInList getContainerInList(String... nestedKeys) {
+ return new ContainerInListBuilder()
+ .setName("inlist")
+ .setNestedList(getNestedList(nestedKeys))
+ .build();
+ }
+
+ private List<NestedList> getNestedList(String... keys) {
+ final ArrayList<NestedList> nestedList = new ArrayList<>();
+ for (String key : keys) {
+ nestedList.add(getSingleNestedList(key));
+ }
+ return nestedList;
+ }
+
+ private NestedList getSingleNestedList(final String key) {
+ return new NestedListBuilder()
+ .setNestedId(key)
+ .setNestedName(key)
+ .build();
+ }
+
+ private void writeContainerWithChoice(final DataModification dataModification) {
+ writeContainerWithChoice(dataModification, getContainerWithChoiceWithComplexCase());
+ }
+
+
+ private void deleteContainerWithChoice(final DataModification dataModification) {
+ dataModification.delete(serializer.toYangInstanceIdentifier(Ids.CONTAINER_WITH_CHOICE_ID));
+ }
+
+ private void writeContainerWithChoice(final DataModification dataModification,
+ final ContainerWithChoice containerWithChoice) {
+ final Map.Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> normalizedNode =
+ serializer.toNormalizedNode(Ids.CONTAINER_WITH_CHOICE_ID, containerWithChoice);
+ dataModification.write(normalizedNode.getKey(), normalizedNode.getValue());
+ }
+
+ private ContainerWithChoice getContainerWithChoiceWithComplexCase() {
+ return new ContainerWithChoiceBuilder()
+ .setLeafFromGrouping("fromG")
+ .setName("name")
+ .setContainerFromGrouping(getContainerFromGrouping())
+ .setChoice(getComplexCase())
+ .build();
+ }
+
+ private Choice getComplexCase() {
+ return new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.choice.choice.C3Builder()
+ .setC3(getC3())
+ .build();
+ }
+
+ private C3 getC3() {
+ return new C3Builder()
+ .setName("c3")
+ .build();
+ }
+
+ private void writeContainerFromGrouping(final DataModification dataModification) {
+ final Map.Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> normalizedNode =
+ serializer.toNormalizedNode(Ids.CONTAINER_FROM_GROUPING_ID, getContainerFromGrouping());
+ dataModification.write(normalizedNode.getKey(), normalizedNode.getValue());
+ }
+
+ private ContainerFromGrouping getContainerFromGrouping() {
+ return new ContainerFromGroupingBuilder()
+ .setLeafInContainerFromGrouping(111)
+ .build();
+ }
+
+
+ private void writeSimpleContainer(final DataModification dataModification) {
+ final Map.Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> normalizedNode =
+ serializer.toNormalizedNode(Ids.SIMPLE_CONTAINER_ID, getSimpleContainer());
+ dataModification.write(normalizedNode.getKey(), normalizedNode.getValue());
+ }
+
+ private void deleteSimpleContainer(final DataModification dataModification) {
+ final YangInstanceIdentifier yangId =
+ serializer.toYangInstanceIdentifier(Ids.SIMPLE_CONTAINER_ID);
+ dataModification.delete(yangId);
+ }
+
+ private SimpleContainer getSimpleContainer() {
+ return new SimpleContainerBuilder()
+ .setSimpleContainerName("n")
+ .addAugmentation(SimpleAugment.class, getSimpleAugment())
+ .addAugmentation(ComplexAugment.class, getComplexAugment())
+ .build();
+ }
+
+ private ComplexAugment getComplexAugment() {
+ return new ComplexAugmentBuilder()
+ .setComplexAugmentContainer(getComplexAugmentContainer())
+ .build();
+ }
+
+ private ComplexAugmentContainer getComplexAugmentContainer() {
+ return new ComplexAugmentContainerBuilder().setSomeLeaf("s").build();
+ }
+
+ private SimpleAugment getSimpleAugment() {
+ return new SimpleAugmentBuilder().setSimpleAugmentLeaf("a").build();
+ }
+
+ @Test
+ public void testWriteAndDeleteInTx() throws Exception {
+ final ModifiableDataTreeDelegator modifiableDataTreeDelegator =
+ new ModifiableDataTreeDelegator(serializer, dataTree, writerRegistry, contextBroker);
+
+ final DataModification dataModification = modifiableDataTreeDelegator.newModification();
+ // Now write everything we can
+ writeSimpleContainer(dataModification);
+ deleteSimpleContainer(dataModification);
+ dataModification.commit();
+
+ verify(simpleContainerWriter).getManagedDataObjectType();
+ // No modification
+ verifyNoMoreInteractions(simpleContainerWriter);
+ }
+
+ @Test
+ public void testSubtreeWriter() throws Exception {
+ writerRegistry = new FlatWriterRegistryBuilder()
+ // Handles also container from grouping
+ .subtreeAdd(Sets.newHashSet(Ids.CONTAINER_FROM_GROUPING_ID), containerWithChoiceWriter)
+ .build();
+
+ final ModifiableDataTreeDelegator modifiableDataTreeDelegator =
+ new ModifiableDataTreeDelegator(serializer, dataTree, writerRegistry, contextBroker);
+
+ final ContainerWithChoice containerWithChoice =
+ new ContainerWithChoiceBuilder().setContainerFromGrouping(getContainerFromGrouping()).build();
+
+ // Test write subtree node
+ DataModification dataModification = modifiableDataTreeDelegator.newModification();
+ writeContainerFromGrouping(dataModification);
+ dataModification.commit();
+
+ verify(containerWithChoiceWriter, atLeastOnce()).getManagedDataObjectType();
+ verify(containerWithChoiceWriter)
+ .update(eq(Ids.CONTAINER_WITH_CHOICE_ID), eq(null), eq(containerWithChoice), any(WriteContext.class));
+ verifyNoMoreInteractions(containerWithChoiceWriter);
+
+ // Test delete sub-node
+ dataModification = modifiableDataTreeDelegator.newModification();
+ final ContainerWithChoice containerWithChoiceEmpty = new ContainerWithChoiceBuilder().build();
+ deleteContainerFromGrouping(dataModification);
+ dataModification.commit();
+
+ verify(containerWithChoiceWriter, atLeastOnce()).getManagedDataObjectType();
+ verify(containerWithChoiceWriter)
+ .update(eq(Ids.CONTAINER_WITH_CHOICE_ID), eq(containerWithChoice), eq(containerWithChoiceEmpty), any(WriteContext.class));
+ verifyNoMoreInteractions(containerWithChoiceWriter);
+
+ // Test write with subtree node that's not handled by subtree writer
+ dataModification = modifiableDataTreeDelegator.newModification();
+ writeContainerWithChoice(dataModification);
+ try {
+ dataModification.commit();
+ fail("Missing writer for C3 should occur");
+ } catch (IllegalArgumentException e) {
+ return;
+ }
+ }
+
+ private void deleteContainerFromGrouping(final DataModification dataModification) {
+ dataModification.delete(serializer.toYangInstanceIdentifier(Ids.CONTAINER_FROM_GROUPING_ID));
+ }
+} \ No newline at end of file
diff --git a/infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/Ids.java b/infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/Ids.java
new file mode 100644
index 0000000..200f50c
--- /dev/null
+++ b/infra/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/Ids.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.data.impl;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ComplexAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithChoice;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleContainer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.choice.choice.c3.C3;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.container.in.list.NestedList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.simple.container.ComplexAugmentContainer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.some.attributes.ContainerFromGrouping;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Instance identifiers referencing all complex nodes within IT test-model.
+ */
+interface Ids {
+
+ // Simple container
+ // ORDER = 3
+ InstanceIdentifier<SimpleContainer> SIMPLE_CONTAINER_ID = InstanceIdentifier.create(SimpleContainer.class);
+ // 2
+ InstanceIdentifier<SimpleAugment> SIMPLE_AUGMENT_ID = SIMPLE_CONTAINER_ID.augmentation(SimpleAugment.class);
+ // UNORDERED
+ InstanceIdentifier<ComplexAugment> COMPLEX_AUGMENT_ID = SIMPLE_CONTAINER_ID.augmentation(ComplexAugment.class);
+ // 1
+ InstanceIdentifier<ComplexAugmentContainer> COMPLEX_AUGMENT_CONTAINER_ID = COMPLEX_AUGMENT_ID.child(ComplexAugmentContainer.class);
+ // Container with list
+ // 9
+ InstanceIdentifier<ContainerWithList> CONTAINER_WITH_LIST_ID = InstanceIdentifier.create(ContainerWithList.class);
+ // 7
+ InstanceIdentifier<ListInContainer> LIST_IN_CONTAINER_ID = CONTAINER_WITH_LIST_ID.child(ListInContainer.class);
+ // 8
+ InstanceIdentifier<ContainerInList> CONTAINER_IN_LIST_ID = LIST_IN_CONTAINER_ID.child(ContainerInList.class);
+ // 6
+ InstanceIdentifier<NestedList> NESTED_LIST_ID = CONTAINER_IN_LIST_ID.child(NestedList.class);
+ // Container with choice
+ // 4
+ InstanceIdentifier<ContainerWithChoice> CONTAINER_WITH_CHOICE_ID = InstanceIdentifier.create(ContainerWithChoice.class);
+ // 2
+ InstanceIdentifier<C3> C3_ID = CONTAINER_WITH_CHOICE_ID.child(C3.class);
+ // 5
+ InstanceIdentifier<ContainerFromGrouping> CONTAINER_FROM_GROUPING_ID = CONTAINER_WITH_CHOICE_ID.child(ContainerFromGrouping.class);
+}
diff --git a/infra/it/pom.xml b/infra/it/pom.xml
new file mode 100644
index 0000000..e565f22
--- /dev/null
+++ b/infra/it/pom.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<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">
+
+ <groupId>io.fd.honeycomb.common</groupId>
+ <artifactId>honeycomb-it-aggregator</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <name>honeycomb</name>
+ <packaging>pom</packaging>
+ <modelVersion>4.0.0</modelVersion>
+ <prerequisites>
+ <maven>3.1.1</maven>
+ </prerequisites>
+ <modules>
+ <module>test-model</module>
+ <module>it-test</module>
+ </modules>
+ <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-install-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/infra/it/test-model/pom.xml b/infra/it/test-model/pom.xml
new file mode 100644
index 0000000..2f087ed
--- /dev/null
+++ b/infra/it/test-model/pom.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<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">
+ <parent>
+ <groupId>io.fd.honeycomb.common</groupId>
+ <artifactId>api-parent</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <relativePath>../../../common/api-parent</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>io.fd.honeycomb</groupId>
+ <artifactId>honeycomb-test-model</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.mdsal.model</groupId>
+ <artifactId>yang-ext</artifactId>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/infra/it/test-model/src/main/yang/hc-test.yang b/infra/it/test-model/src/main/yang/hc-test.yang
new file mode 100644
index 0000000..e13b500
--- /dev/null
+++ b/infra/it/test-model/src/main/yang/hc-test.yang
@@ -0,0 +1,123 @@
+module hc-test {
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:hc:test";
+ prefix "hct";
+
+ revision "2015-01-05" {
+ description "Testing HC model with bindings";
+ }
+
+ import yang-ext {
+ prefix "ext";
+ }
+
+ // WRITE ORDER 3
+ // READ ORDER 1
+ container simple-container {
+ leaf simple-container-name {
+ type string;
+ }
+ }
+
+ grouping some-attributes {
+ leaf leaf-from-grouping {
+ type string;
+ }
+
+ // WRITE ORDER 5
+ container container-from-grouping {
+ leaf leaf-in-container-from-grouping {
+ type int32;
+ }
+ }
+ }
+
+ // WRITE ORDER 9 (no real attributes though)
+ // READ ORDER 2
+ container container-with-list {
+ // WRITE ORDER 7
+ // READ ORDER 2.1
+ list list-in-container {
+ key "id";
+ ordered-by "user";
+
+ leaf id {
+ type uint32;
+ }
+
+ // WRITE ORDER 8
+ // READ ORDER 2.1.1
+ container container-in-list {
+ leaf name {
+ type string;
+ }
+
+ // WRITE ORDER 6
+ // READ ORDER 2.1.1.1
+ list nested-list {
+ key "nested-id";
+ ordered-by "user";
+
+ leaf nested-id {
+ type string;
+ }
+
+ leaf nested-name {
+ type string;
+ }
+ }
+ }
+ }
+ }
+
+ // WRITE ORDER 4
+ container container-with-choice {
+ leaf name {
+ type string;
+ }
+
+ uses some-attributes;
+
+ choice choice {
+ leaf c1 {
+ type string;
+ }
+
+ leaf c2 {
+ type string;
+ }
+
+ // WRITE ORDER: 2
+ container c3 {
+ leaf name {
+ type string;
+ }
+ }
+ }
+ }
+
+ // WRITE ORDER: 2
+ // READ ORDER 1.1
+ augment "/hct:simple-container" {
+ ext:augment-identifier "simple-augment";
+
+ leaf simple-augment-leaf {
+ type string;
+ }
+ }
+
+ // WRITE UNORDERED
+ // READ ORDER 1.2
+ augment "/hct:simple-container" {
+ ext:augment-identifier "complex-augment";
+
+ // WRITE ORDER: 1
+ // READ ORDER 1.2.1
+ container complex-augment-container {
+ leaf some-leaf {
+ type string;
+ }
+ }
+ }
+
+}
diff --git a/infra/karaf/pom.xml b/infra/karaf/pom.xml
new file mode 100644
index 0000000..6cee029
--- /dev/null
+++ b/infra/karaf/pom.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<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">
+ <parent>
+ <groupId>io.fd.honeycomb.common</groupId>
+ <artifactId>karaf-parent</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <relativePath>../../common/karaf-parent</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>io.fd.honeycomb</groupId>
+ <artifactId>honeycomb-karaf</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <name>${project.artifactId}</name>
+ <prerequisites>
+ <maven>3.1.1</maven>
+ </prerequisites>
+ <properties>
+ <karaf.localFeature>odl-honeycomb-ui</karaf.localFeature>
+ </properties>
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>honeycomb-artifacts</artifactId>
+ <version>${project.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+ <dependencies>
+ <dependency>
+ <!-- scope is compile so all features (there is only one) are installed
+ into startup.properties and the feature repo itself is not installed -->
+ <groupId>org.apache.karaf.features</groupId>
+ <artifactId>framework</artifactId>
+ <type>kar</type>
+ </dependency>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>honeycomb-features</artifactId>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ </dependencies>
+ <!-- DO NOT install or deploy the karaf artifact -->
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/infra/notification/api/pom.xml b/infra/notification/api/pom.xml
new file mode 100644
index 0000000..2291025
--- /dev/null
+++ b/infra/notification/api/pom.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<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">
+ <parent>
+ <groupId>io.fd.honeycomb.common</groupId>
+ <artifactId>impl-parent</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <relativePath>../../../common/impl-parent</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>io.fd.honeycomb</groupId>
+ <artifactId>notification-api</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-dom-api</artifactId>
+ <version>2.0.2-Beryllium-SR2</version>
+ </dependency>
+ </dependencies>
+
+
+</project>
diff --git a/infra/notification/api/src/main/java/io/fd/honeycomb/v3po/notification/ManagedNotificationProducer.java b/infra/notification/api/src/main/java/io/fd/honeycomb/v3po/notification/ManagedNotificationProducer.java
new file mode 100644
index 0000000..0f5e28c
--- /dev/null
+++ b/infra/notification/api/src/main/java/io/fd/honeycomb/v3po/notification/ManagedNotificationProducer.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.fd.honeycomb.v3po.notification;
+
+import com.google.common.annotations.Beta;
+import javax.annotation.Nonnull;
+
+/**
+ * Special notification producer that is capable of starting and stopping the notification stream
+ */
+@Beta
+public interface ManagedNotificationProducer extends NotificationProducer {
+
+ /**
+ * Start notification stream managed by this producer.
+ *
+ * @param collector Notification collector expected to collect produced notifications
+ */
+ void start(@Nonnull NotificationCollector collector);
+
+ /**
+ * Stop notification stream managed by this producer.
+ */
+ void stop();
+}
diff --git a/infra/notification/api/src/main/java/io/fd/honeycomb/v3po/notification/NotificationCollector.java b/infra/notification/api/src/main/java/io/fd/honeycomb/v3po/notification/NotificationCollector.java
new file mode 100644
index 0000000..406ab03
--- /dev/null
+++ b/infra/notification/api/src/main/java/io/fd/honeycomb/v3po/notification/NotificationCollector.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.fd.honeycomb.v3po.notification;
+
+import com.google.common.annotations.Beta;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.binding.Notification;
+
+/**
+ * Notification collector. Collects all the notifications, which are further
+ * propagated to all wired northbound interfaces.
+ */
+@Beta
+public interface NotificationCollector extends AutoCloseable, NotificationProducer {
+
+ /**
+ * Publish a single notification.
+ *
+ * @param notification notification to be published
+ */
+ void onNotification(@Nonnull Notification notification);
+}
diff --git a/infra/notification/api/src/main/java/io/fd/honeycomb/v3po/notification/NotificationProducer.java b/infra/notification/api/src/main/java/io/fd/honeycomb/v3po/notification/NotificationProducer.java
new file mode 100644
index 0000000..dab773c
--- /dev/null
+++ b/infra/notification/api/src/main/java/io/fd/honeycomb/v3po/notification/NotificationProducer.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.fd.honeycomb.v3po.notification;
+
+import com.google.common.annotations.Beta;
+import java.util.Collection;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.binding.Notification;
+
+/**
+ * Produces notification of exposed notification types
+ */
+@Beta
+public interface NotificationProducer extends AutoCloseable {
+
+ /**
+ * Return collection of notification types that will be emitted by this producer.
+ * Other types of notifications should not be emitted, since they can be rejected.
+ *
+ * @return collection of all notification types emitted by this producer
+ */
+ @Nonnull
+ Collection<Class<? extends Notification>> getNotificationTypes();
+}
diff --git a/infra/notification/api/src/main/yang/notification-api.yang b/infra/notification/api/src/main/yang/notification-api.yang
new file mode 100644
index 0000000..4e6eb98
--- /dev/null
+++ b/infra/notification/api/src/main/yang/notification-api.yang
@@ -0,0 +1,31 @@
+module notification-api {
+ yang-version 1;
+ namespace "urn:honeycomb:params:xml:ns:yang:notification:api";
+ prefix "hc-notif-a";
+
+ import config { prefix config; revision-date 2013-04-05; }
+
+ description
+ "Module definition for honeycomb notification service APIs";
+
+ revision "2016-06-01" {
+ description
+ "Initial revision";
+ }
+
+ identity honeycomb-notification-collector {
+ base "config:service-type";
+ config:java-class io.fd.honeycomb.v3po.notification.NotificationCollector;
+ }
+
+ identity dom-notification-service {
+ base "config:service-type";
+ config:java-class org.opendaylight.controller.md.sal.dom.broker.impl.DOMNotificationRouter;
+ }
+
+ identity honeycomb-notification-producer {
+ base "config:service-type";
+ config:java-class io.fd.honeycomb.v3po.notification.ManagedNotificationProducer;
+ }
+
+}
diff --git a/infra/notification/impl/pom.xml b/infra/notification/impl/pom.xml
new file mode 100644
index 0000000..9fa5424
--- /dev/null
+++ b/infra/notification/impl/pom.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<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">
+ <parent>
+ <groupId>io.fd.honeycomb.common</groupId>
+ <artifactId>impl-parent</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <relativePath>../../../common/impl-parent</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>io.fd.honeycomb</groupId>
+ <artifactId>notification-impl</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>notification-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-config</artifactId>
+ <version>1.3.2-Beryllium-SR2</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.opendaylight.netconf</groupId>
+ <artifactId>netconf-notifications-api</artifactId>
+ <version>1.0.2-Beryllium-SR2</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-artifacts</id>
+ <goals>
+ <goal>attach-artifact</goal>
+ </goals>
+ <phase>package</phase>
+ <configuration>
+ <artifacts>
+ <artifact>
+ <file>${config.file}</file>
+ <type>xml</type>
+ <classifier>config</classifier>
+ </artifact>
+ <artifact>
+ <file>src/main/config/notification-to-netconf-config.xml</file>
+ <type>xml</type>
+ <classifier>notification2netconf</classifier>
+ </artifact>
+ </artifacts>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/infra/notification/impl/src/main/config/default-config.xml b/infra/notification/impl/src/main/config/default-config.xml
new file mode 100644
index 0000000..2b91de4
--- /dev/null
+++ b/infra/notification/impl/src/main/config/default-config.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<snapshot>
+ <required-capabilities>
+ <capability>urn:honeycomb:params:xml:ns:yang:notification:impl?module=notification-impl&amp;revision=2016-06-01</capability>
+ </required-capabilities>
+ <configuration>
+
+ <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <!-- Underlying dom notification service(router)-->
+ <module>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:notification:impl">prefix:honeycomb-dom-notification-service</type>
+ <name>honeycomb-dom-notification-service</name>
+ <queue-depth>1024</queue-depth>
+ </module>
+
+ <!-- Honeycomb notification collector built on top of dom notification service-->
+ <module>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:notification:impl">prefix:honeycomb-notification-manager</type>
+ <name>honeycomb-notification-manager</name>
+ <runtime-mapping-codec>
+ <type xmlns:binding-impl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding-impl:binding-dom-mapping-service</type>
+ <name>runtime-mapping-singleton</name>
+ </runtime-mapping-codec>
+ <dom-notification-service>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:notification:api">prefix:dom-notification-service</type>
+ <name>honeycomb-dom-notification-service</name>
+ </dom-notification-service>
+ <!-- Here goes list of producers. They will register themselves from plugins -->
+ <!--<notification-producers>-->
+ <!--</notification-producers>-->
+ </module>
+
+ </modules>
+
+ <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <service>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:notification:api">prefix:dom-notification-service</type>
+ <instance>
+ <name>honeycomb-dom-notification-service</name>
+ <provider>/modules/module[type='honeycomb-dom-notification-service'][name='honeycomb-dom-notification-service']</provider>
+ </instance>
+ </service>
+ <service>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:notification:api">prefix:honeycomb-notification-collector</type>
+ <instance>
+ <name>honeycomb-notification-manager</name>
+ <provider>/modules/module[type='honeycomb-notification-manager'][name='honeycomb-notification-manager']</provider>
+ </instance>
+ </service>
+
+ </services>
+ </data>
+ </configuration>
+</snapshot>
+
diff --git a/infra/notification/impl/src/main/config/notification-to-netconf-config.xml b/infra/notification/impl/src/main/config/notification-to-netconf-config.xml
new file mode 100644
index 0000000..d2aac09
--- /dev/null
+++ b/infra/notification/impl/src/main/config/notification-to-netconf-config.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<snapshot>
+<required-capabilities>
+ <capability>urn:honeycomb:params:xml:ns:yang:notification:impl?module=notification-impl&amp;revision=2016-06-01</capability>
+</required-capabilities>
+<configuration>
+
+ <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <module>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:notification:impl">prefix:honeycomb-notification-to-netconf-translator</type>
+ <name>honeycomb-notification-to-netconf-translator</name>
+ <netconf-notification-registry>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:notification">
+ prefix:netconf-notification-registry
+ </type>
+ <name>vpp-netconf-notification-manager</name>
+ </netconf-notification-registry>
+ <netconf-notification-collector>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:netconf:northbound:notification">
+ prefix:netconf-notification-collector
+ </type>
+ <name>vpp-netconf-notification-manager</name>
+ </netconf-notification-collector>
+ <schema-service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+ <name>yang-schema-service</name>
+ </schema-service>
+ <honeycomb-notification-collector>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:notification:api">prefix:honeycomb-notification-collector</type>
+ <name>honeycomb-notification-manager</name>
+ </honeycomb-notification-collector>
+ <dom-notification-service>
+ <type xmlns:prefix="urn:honeycomb:params:xml:ns:yang:notification:api">prefix:dom-notification-service</type>
+ <name>honeycomb-dom-notification-service</name>
+ </dom-notification-service>
+ <netconf-stream-name>honeycomb</netconf-stream-name>
+ <netconf-stream-description>All notifications received by honeycomb's plugins</netconf-stream-description>
+ </module>
+ </modules>
+ </data>
+</configuration>
+</snapshot>
diff --git a/infra/notification/impl/src/main/java/io/fd/honeycomb/v3po/notification/impl/HoneycombNotificationCollector.java b/infra/notification/impl/src/main/java/io/fd/honeycomb/v3po/notification/impl/HoneycombNotificationCollector.java
new file mode 100644
index 0000000..e7d54e3
--- /dev/null
+++ b/infra/notification/impl/src/main/java/io/fd/honeycomb/v3po/notification/impl/HoneycombNotificationCollector.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.fd.honeycomb.v3po.notification.impl;
+
+import io.fd.honeycomb.v3po.notification.NotificationCollector;
+import java.util.Collection;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
+import org.opendaylight.yangtools.yang.binding.Notification;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Notification collector based on MD-SAL's {@link NotificationPublishService}.
+ */
+public final class HoneycombNotificationCollector implements NotificationCollector, AutoCloseable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(HoneycombNotificationCollector.class);
+
+ private final NotificationPublishService bindingDOMNotificationPublishServiceAdapter;
+ private final NotificationProducerRegistry notificationProducerRegistry;
+
+ public HoneycombNotificationCollector(
+ @Nonnull final NotificationPublishService bindingDOMNotificationPublishServiceAdapter,
+ @Nonnull final NotificationProducerRegistry notificationProducerRegistry) {
+ this.bindingDOMNotificationPublishServiceAdapter = bindingDOMNotificationPublishServiceAdapter;
+ this.notificationProducerRegistry = notificationProducerRegistry;
+ }
+
+ @Override
+ public void close() throws Exception {
+ LOG.trace("Closing");
+ }
+
+ @Override
+ public void onNotification(@Nonnull final Notification notification) {
+ LOG.debug("Notification: {} pushed into collector", notification.getClass().getSimpleName());
+ LOG.trace("Notification: {} pushed into collector", notification);
+ try {
+ bindingDOMNotificationPublishServiceAdapter.putNotification(notification);
+ } catch (InterruptedException e) {
+ LOG.warn("Interrupted", e);
+ Thread.currentThread().interrupt();
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ @Nonnull
+ public Collection<Class<? extends Notification>> getNotificationTypes() {
+ return notificationProducerRegistry.getNotificationTypes();
+ }
+}
diff --git a/infra/notification/impl/src/main/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerRegistry.java b/infra/notification/impl/src/main/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerRegistry.java
new file mode 100644
index 0000000..8fba700
--- /dev/null
+++ b/infra/notification/impl/src/main/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerRegistry.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.fd.honeycomb.v3po.notification.impl;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import io.fd.honeycomb.v3po.notification.ManagedNotificationProducer;
+import io.fd.honeycomb.v3po.notification.NotificationProducer;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import javax.annotation.concurrent.ThreadSafe;
+import org.opendaylight.yangtools.yang.binding.Notification;
+import org.opendaylight.yangtools.yang.common.QName;
+
+/**
+ * Holds the collection of registered notification producers.
+ * Provides additional information about the types of notifications produced per producer and overall.
+ */
+@ThreadSafe
+public final class NotificationProducerRegistry {
+
+ private final Set<Class<? extends Notification>> notificationTypes;
+ private final Map<QName, ManagedNotificationProducer> notificationQNameToProducer;
+ private final Multimap<ManagedNotificationProducer, QName> notificationProducerQNames;
+
+ public NotificationProducerRegistry(final List<ManagedNotificationProducer> notificationProducersDependency) {
+ this.notificationTypes = toTypes(notificationProducersDependency);
+ this.notificationQNameToProducer = toQNameMap(notificationProducersDependency);
+ this.notificationProducerQNames = toQNameMapReversed(notificationProducersDependency);
+ }
+
+ private static Multimap<ManagedNotificationProducer, QName> toQNameMapReversed(final List<ManagedNotificationProducer> notificationProducers) {
+ final Multimap<ManagedNotificationProducer, QName> multimap = HashMultimap.create();
+
+ for (ManagedNotificationProducer producer : notificationProducers) {
+ for (Class<? extends Notification> aClass : producer.getNotificationTypes()) {
+ multimap.put(producer, getQName(aClass));
+ }
+ }
+ return multimap;
+ }
+
+ private static Set<Class<? extends Notification>> toTypes(final List<ManagedNotificationProducer> notificationProducersDependency) {
+ // Get all notification types registered from HC notification producers
+ return notificationProducersDependency
+ .stream()
+ .flatMap(producer -> producer.getNotificationTypes().stream())
+ .collect(Collectors.toSet());
+ }
+
+
+ private static Map<QName, ManagedNotificationProducer> toQNameMap(final List<ManagedNotificationProducer> producerDependencies) {
+ // Only a single notification producer per notification type is allowed
+ final Map<QName, ManagedNotificationProducer> qNamesToProducers = Maps.newHashMap();
+ for (ManagedNotificationProducer notificationProducer : producerDependencies) {
+ for (QName qName : typesToQNames(notificationProducer.getNotificationTypes())) {
+ final NotificationProducer previousProducer = qNamesToProducers.put(qName, notificationProducer);
+ checkArgument(previousProducer == null, "2 producers of the same notification type: %s. " +
+ "Producer 1: {} Producer 2: {}" , qName, previousProducer, notificationProducer);
+ }
+ }
+ return qNamesToProducers;
+ }
+
+
+ private static Set<QName> typesToQNames(final Collection<Class<? extends Notification>> notificationTypes) {
+ return notificationTypes
+ .stream()
+ .map(NotificationProducerRegistry::getQName)
+ .collect(Collectors.toSet());
+ }
+
+
+ public static QName getQName(final Class<? extends Notification> aClass) {
+ try {
+ return (QName) aClass.getField("QNAME").get(null);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ throw new IllegalArgumentException("Unable to retrieve QName for notification of type: " + aClass, e);
+ }
+ }
+
+ Set<Class<? extends Notification>> getNotificationTypes() {
+ return notificationTypes;
+ }
+
+ Map<QName, ManagedNotificationProducer> getNotificationQNameToProducer() {
+ return notificationQNameToProducer;
+ }
+
+ Multimap<ManagedNotificationProducer, QName> getNotificationProducerQNames() {
+ return notificationProducerQNames;
+ }
+}
diff --git a/infra/notification/impl/src/main/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerTracker.java b/infra/notification/impl/src/main/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerTracker.java
new file mode 100644
index 0000000..cefb50a
--- /dev/null
+++ b/infra/notification/impl/src/main/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerTracker.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.fd.honeycomb.v3po.notification.impl;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.collect.Sets;
+import io.fd.honeycomb.v3po.notification.ManagedNotificationProducer;
+import io.fd.honeycomb.v3po.notification.NotificationCollector;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import javax.annotation.concurrent.ThreadSafe;
+import org.opendaylight.controller.md.sal.dom.spi.DOMNotificationSubscriptionListener;
+import org.opendaylight.controller.md.sal.dom.spi.DOMNotificationSubscriptionListenerRegistry;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Starts & stops notification producer dependencies on demand.
+ * Uses {@link DOMNotificationSubscriptionListenerRegistry} to receive subscription change notifications.
+ */
+@ThreadSafe
+public final class NotificationProducerTracker
+ implements DOMNotificationSubscriptionListener, AutoCloseable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NotificationProducerTracker.class);
+
+ private final ListenerRegistration<NotificationProducerTracker> subscriptionListener;
+ private final NotificationProducerRegistry registry;
+ private final NotificationCollector collector;
+
+ private final Set<ManagedNotificationProducer> alreadyStartedProducers = new HashSet<>();
+
+ public NotificationProducerTracker(@Nonnull final NotificationProducerRegistry registry,
+ @Nonnull final NotificationCollector collector,
+ @Nonnull final DOMNotificationSubscriptionListenerRegistry notificationRouter) {
+ this.registry = registry;
+ this.collector = collector;
+ this.subscriptionListener = notificationRouter.registerSubscriptionListener(this);
+ }
+
+ @Override
+ public synchronized void onSubscriptionChanged(final Set<SchemaPath> set) {
+ LOG.debug("Subscriptions changed. Current subscriptions: {}", set);
+ final Set<QName> currentSubscriptions = set.stream().map(SchemaPath::getLastComponent).collect(Collectors.toSet());
+ final Set<QName> startedQNames = getStartedQNames(alreadyStartedProducers);
+ final Sets.SetView<QName> newSubscriptions = Sets.difference(currentSubscriptions, startedQNames);
+ LOG.debug("Subscriptions changed. New subscriptions: {}", newSubscriptions);
+ final Sets.SetView<QName> deletedSubscriptions = Sets.difference(startedQNames, currentSubscriptions);
+ LOG.debug("Subscriptions changed. Deleted subscriptions: {}", deletedSubscriptions);
+
+ newSubscriptions.stream().forEach(newSub -> {
+ if(!registry.getNotificationQNameToProducer().containsKey(newSub)) {
+ return;
+ }
+ final ManagedNotificationProducer producer = registry.getNotificationQNameToProducer().get(newSub);
+ if(alreadyStartedProducers.contains(producer)) {
+ return;
+ }
+ LOG.debug("Starting notification producer: {}", producer);
+ producer.start(collector);
+ alreadyStartedProducers.add(producer);
+ });
+
+ deletedSubscriptions.stream().forEach(newSub -> {
+ checkState(registry.getNotificationQNameToProducer().containsKey(newSub));
+ final ManagedNotificationProducer producer = registry.getNotificationQNameToProducer().get(newSub);
+ checkState(alreadyStartedProducers.contains(producer));
+ LOG.debug("Stopping notification producer: {}", producer);
+ producer.stop();
+ alreadyStartedProducers.remove(producer);
+ });
+
+ }
+
+ private Set<QName> getStartedQNames(final Set<ManagedNotificationProducer> alreadyStartedProducers) {
+ return alreadyStartedProducers.stream()
+ .flatMap(p -> registry.getNotificationProducerQNames().get(p).stream())
+ .collect(Collectors.toSet());
+ }
+
+ @Override
+ public synchronized void close() throws Exception {
+ LOG.trace("Closing");
+ subscriptionListener.close();
+ // Stop all producers
+ LOG.debug("Stopping all producers: {}", alreadyStartedProducers);
+ alreadyStartedProducers.forEach(ManagedNotificationProducer::stop);
+ alreadyStartedProducers.clear();
+ }
+}
diff --git a/infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombDomNotificationServiceModule.java b/infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombDomNotificationServiceModule.java
new file mode 100644
index 0000000..9a9c7de
--- /dev/null
+++ b/infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombDomNotificationServiceModule.java
@@ -0,0 +1,27 @@
+package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.notification.impl.rev160601;
+
+import org.opendaylight.controller.config.api.JmxAttributeValidationException;
+import org.opendaylight.controller.md.sal.dom.broker.impl.DOMNotificationRouter;
+
+public class HoneycombDomNotificationServiceModule extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.notification.impl.rev160601.AbstractHoneycombDomNotificationServiceModule {
+ public HoneycombDomNotificationServiceModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public HoneycombDomNotificationServiceModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.notification.impl.rev160601.HoneycombDomNotificationServiceModule oldModule, java.lang.AutoCloseable oldInstance) {
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ public void customValidation() {
+ JmxAttributeValidationException.checkCondition(getQueueDepth() > 0, "Queue depth must be > 0", queueDepthJmxAttribute);
+ }
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+ // Create DOMNotificationRouter to do the heavy lifting for HoneycombNotificationCollector
+ // It creates executor internally
+ return DOMNotificationRouter.create(getQueueDepth());
+ }
+
+}
diff --git a/infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombDomNotificationServiceModuleFactory.java b/infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombDomNotificationServiceModuleFactory.java
new file mode 100644
index 0000000..d3603ac
--- /dev/null
+++ b/infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombDomNotificationServiceModuleFactory.java
@@ -0,0 +1,13 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: notification-impl yang module local name: honeycomb-dom-notification-service
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Wed Jun 08 09:49:08 CEST 2016
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.notification.impl.rev160601;
+public class HoneycombDomNotificationServiceModuleFactory extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.notification.impl.rev160601.AbstractHoneycombDomNotificationServiceModuleFactory {
+
+}
diff --git a/infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombNotificationManagerModule.java b/infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombNotificationManagerModule.java
new file mode 100644
index 0000000..4a9440c
--- /dev/null
+++ b/infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombNotificationManagerModule.java
@@ -0,0 +1,93 @@
+package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.notification.impl.rev160601;
+
+import io.fd.honeycomb.v3po.notification.NotificationCollector;
+import io.fd.honeycomb.v3po.notification.NotificationProducer;
+import io.fd.honeycomb.v3po.notification.impl.HoneycombNotificationCollector;
+import io.fd.honeycomb.v3po.notification.impl.NotificationProducerRegistry;
+import io.fd.honeycomb.v3po.notification.impl.NotificationProducerTracker;
+import java.util.Collection;
+import org.opendaylight.controller.md.sal.binding.impl.BindingDOMNotificationPublishServiceAdapter;
+import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
+import org.opendaylight.controller.md.sal.dom.broker.impl.DOMNotificationRouter;
+import org.opendaylight.yangtools.yang.binding.Notification;
+
+public class HoneycombNotificationManagerModule extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.notification.impl.rev160601.AbstractHoneycombNotificationManagerModule {
+
+ public HoneycombNotificationManagerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public HoneycombNotificationManagerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.notification.impl.rev160601.HoneycombNotificationManagerModule oldModule, java.lang.AutoCloseable oldInstance) {
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ public void customValidation() {
+ // add custom validation form module attributes here.
+ }
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+ final DOMNotificationRouter notificationRouter = getDomNotificationServiceDependency();
+
+ // Create the registry to keep track of what's registered
+ final NotificationProducerRegistry notificationProducerRegistry =
+ new NotificationProducerRegistry(getNotificationProducersDependency());
+
+ // Create BA version of notification service (implementation is free from ODL)
+ final BindingToNormalizedNodeCodec codec = getRuntimeMappingCodecDependency();
+ final BindingDOMNotificationPublishServiceAdapter bindingDOMNotificationPublishServiceAdapter =
+ new BindingDOMNotificationPublishServiceAdapter(codec, notificationRouter);
+
+ // Create Collector on top of BA notification service and registry
+ final HoneycombNotificationCollector honeycombNotificationCollector =
+ new HoneycombNotificationCollector(bindingDOMNotificationPublishServiceAdapter, notificationProducerRegistry);
+
+ // Create tracker, responsible for starting and stopping registered notification producers whenever necessary
+ final NotificationProducerTracker notificationProducerTracker =
+ new NotificationProducerTracker(notificationProducerRegistry, honeycombNotificationCollector,
+ notificationRouter);
+
+ // TODO wire with restconf
+ // DOMNotificationService is already provided by DOMBroker injected into RESTCONF, however RESTCONF
+ // only supports data-change notification, nothing else. So currently its impossible.
+
+ return new CloseableCollector(honeycombNotificationCollector, () -> {
+ // Close all resources in order opposite to instantiation
+ notificationProducerTracker.close();
+ honeycombNotificationCollector.close();
+ bindingDOMNotificationPublishServiceAdapter.close();
+ // notificationProducerRegistry; no close, it's just a collection
+ });
+ }
+
+ /**
+ * NotificationCollector wrapper in which close method execution can be injected
+ */
+ private class CloseableCollector implements AutoCloseable, NotificationCollector, NotificationProducer {
+
+ private final HoneycombNotificationCollector honeycombNotificationCollector;
+ private final AutoCloseable resources;
+
+ CloseableCollector(final HoneycombNotificationCollector honeycombNotificationCollector,
+ final AutoCloseable resources) {
+ this.honeycombNotificationCollector = honeycombNotificationCollector;
+ this.resources = resources;
+ }
+
+ @Override
+ public void close() throws Exception {
+ resources.close();
+ }
+
+ @Override
+ public void onNotification(final Notification notification) {
+ honeycombNotificationCollector.onNotification(notification);
+ }
+
+ @Override
+ public Collection<Class<? extends Notification>> getNotificationTypes() {
+ return honeycombNotificationCollector.getNotificationTypes();
+ }
+ }
+}
diff --git a/infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombNotificationManagerModuleFactory.java b/infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombNotificationManagerModuleFactory.java
new file mode 100644
index 0000000..b12b700
--- /dev/null
+++ b/infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombNotificationManagerModuleFactory.java
@@ -0,0 +1,13 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: notification-impl yang module local name: honeycomb-notification-manager
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Wed Jun 01 16:08:01 CEST 2016
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.notification.impl.rev160601;
+public class HoneycombNotificationManagerModuleFactory extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.notification.impl.rev160601.AbstractHoneycombNotificationManagerModuleFactory {
+
+}
diff --git a/infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombNotificationToNetconfTranslatorModule.java b/infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombNotificationToNetconfTranslatorModule.java
new file mode 100644
index 0000000..4d85d64
--- /dev/null
+++ b/infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombNotificationToNetconfTranslatorModule.java
@@ -0,0 +1,157 @@
+package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.notification.impl.rev160601;
+
+import com.google.common.annotations.VisibleForTesting;
+import io.fd.honeycomb.v3po.notification.NotificationCollector;
+import io.fd.honeycomb.v3po.notification.impl.NotificationProducerRegistry;
+import java.io.IOException;
+import java.util.Set;
+import java.util.stream.Collectors;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import javax.xml.transform.dom.DOMResult;
+import org.opendaylight.controller.config.api.JmxAttributeValidationException;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotificationListener;
+import org.opendaylight.controller.sal.core.api.model.SchemaService;
+import org.opendaylight.netconf.notifications.NetconfNotification;
+import org.opendaylight.netconf.notifications.NotificationPublisherRegistration;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.StreamNameType;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netmod.notification.rev080714.netconf.streams.StreamBuilder;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
+import org.opendaylight.yangtools.yang.data.impl.codec.xml.XMLStreamNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class HoneycombNotificationToNetconfTranslatorModule extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.notification.impl.rev160601.AbstractHoneycombNotificationToNetconfTranslatorModule {
+
+ private static final Logger LOG = LoggerFactory.getLogger(HoneycombNotificationToNetconfTranslatorModule.class);
+
+ public HoneycombNotificationToNetconfTranslatorModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public HoneycombNotificationToNetconfTranslatorModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.notification.impl.rev160601.HoneycombNotificationToNetconfTranslatorModule oldModule, java.lang.AutoCloseable oldInstance) {
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ public void customValidation() {
+ JmxAttributeValidationException.checkCondition(!getNetconfStreamName().isEmpty(),
+ "Stream name cannot be empty", netconfStreamNameJmxAttribute);
+ JmxAttributeValidationException.checkCondition(!getNetconfStreamDescription().isEmpty(),
+ "Stream description cannot be empty", netconfStreamDescriptionJmxAttribute);
+ }
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+ final SchemaService schemaService = getSchemaServiceDependency();
+ final StreamNameType streamType = new StreamNameType(getNetconfStreamName());
+ final NotificationCollector hcNotificationCollector = getHoneycombNotificationCollectorDependency();
+
+ // Register as NETCONF notification publisher under configured name
+ final NotificationPublisherRegistration netconfNotificationProducerReg =
+ getNetconfNotificationCollectorDependency().registerNotificationPublisher(new StreamBuilder()
+ .setName(streamType)
+ .setReplaySupport(false)
+ .setDescription(getNetconfStreamDescription()).build());
+
+ // Notification Translator, get notification from HC producers and put into NETCONF notification collector
+ final DOMNotificationListener domNotificationListener =
+ notification -> {
+ LOG.debug("Propagating notification: {} into NETCONF", notification.getType());
+ netconfNotificationProducerReg.onNotification(streamType, notificationToXml(notification, schemaService.getGlobalContext()));
+ };
+
+ // NotificationManager is used to provide list of available notifications (which are all of the notifications registered)
+ // TODO make available notifications configurable here so that any number of notification streams for NETCONF
+ // can be configured on top of a single notification manager
+ LOG.debug("Current notifications to be exposed over NETCONF: {}", hcNotificationCollector.getNotificationTypes());
+ final Set<SchemaPath> currentNotificationSchemaPaths = hcNotificationCollector.getNotificationTypes()
+ .stream()
+ .map(NotificationProducerRegistry::getQName)
+ .map(qName -> SchemaPath.create(true, qName))
+ .collect(Collectors.toSet());
+
+ // Register as listener to HC's DOM notification service
+ // TODO This should only be triggered when NETCONF notifications are activated
+ // Because this way we actually start all notification producers
+ // final Collection<QName> notificationQNames =
+ final ListenerRegistration<DOMNotificationListener> domNotificationListenerReg = getDomNotificationServiceDependency()
+ .registerNotificationListener(domNotificationListener, currentNotificationSchemaPaths);
+
+ LOG.info("Exposing NETCONF notification stream: {}", streamType.getValue());
+ return () -> {
+ domNotificationListenerReg.close();
+ netconfNotificationProducerReg.close();
+ };
+ }
+
+ @VisibleForTesting
+ static NetconfNotification notificationToXml(final DOMNotification domNotification, final SchemaContext ctx) {
+ LOG.trace("Transforming notification: {} into XML", domNotification.getType());
+
+ final SchemaPath type = domNotification.getType();
+ final QName notificationQName = type.getLastComponent();
+ final DOMResult result = prepareDomResultForRpcRequest(notificationQName);
+
+ try {
+ writeNormalizedRpc(domNotification, result, type, ctx);
+ } catch (final XMLStreamException | IOException | IllegalStateException e) {
+ LOG.warn("Unable to transform notification: {} into XML", domNotification.getType(), e);
+ throw new IllegalArgumentException("Unable to serialize " + type, e);
+ }
+
+ final Document node = result.getNode().getOwnerDocument();
+ return new NetconfNotification(node);
+ }
+
+ private static DOMResult prepareDomResultForRpcRequest(final QName notificationQName) {
+ final Document document = XmlUtil.newDocument();
+ final Element notificationElement =
+ document.createElementNS(notificationQName.getNamespace().toString(), notificationQName.getLocalName());
+ document.appendChild(notificationElement);
+ return new DOMResult(notificationElement);
+ }
+
+ private static final XMLOutputFactory XML_FACTORY;
+
+ static {
+ XML_FACTORY = XMLOutputFactory.newFactory();
+ XML_FACTORY.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, false);
+ }
+
+ private static void writeNormalizedRpc(final DOMNotification normalized, final DOMResult result,
+ final SchemaPath schemaPath, final SchemaContext baseNetconfCtx)
+ throws IOException, XMLStreamException {
+ final XMLStreamWriter writer = XML_FACTORY.createXMLStreamWriter(result);
+ try {
+ try (final NormalizedNodeStreamWriter normalizedNodeStreamWriter =
+ XMLStreamNormalizedNodeStreamWriter.create(writer, baseNetconfCtx, schemaPath)) {
+ try (final NormalizedNodeWriter normalizedNodeWriter =
+ NormalizedNodeWriter.forStreamWriter(normalizedNodeStreamWriter)) {
+ for (DataContainerChild<?, ?> dataContainerChild : normalized.getBody().getValue()) {
+ normalizedNodeWriter.write(dataContainerChild);
+ }
+ normalizedNodeWriter.flush();
+ }
+ }
+ } finally {
+ try {
+ writer.close();
+ } catch (final Exception e) {
+ LOG.warn("Unable to close resource properly. Ignoring", e);
+ }
+ }
+ }
+
+}
diff --git a/infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombNotificationToNetconfTranslatorModuleFactory.java b/infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombNotificationToNetconfTranslatorModuleFactory.java
new file mode 100644
index 0000000..3362230
--- /dev/null
+++ b/infra/notification/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/HoneycombNotificationToNetconfTranslatorModuleFactory.java
@@ -0,0 +1,13 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: notification-impl yang module local name: honeycomb-notification-to-netconf-translator
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Thu Jun 02 14:39:23 CEST 2016
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.notification.impl.rev160601;
+public class HoneycombNotificationToNetconfTranslatorModuleFactory extends org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.notification.impl.rev160601.AbstractHoneycombNotificationToNetconfTranslatorModuleFactory {
+
+}
diff --git a/infra/notification/impl/src/main/yang/notification-impl.yang b/infra/notification/impl/src/main/yang/notification-impl.yang
new file mode 100644
index 0000000..8489975
--- /dev/null
+++ b/infra/notification/impl/src/main/yang/notification-impl.yang
@@ -0,0 +1,141 @@
+module notification-impl {
+ yang-version 1;
+ namespace "urn:honeycomb:params:xml:ns:yang:notification:impl";
+ prefix "hc-notif-i";
+
+ import config { prefix config; revision-date 2013-04-05; }
+ import netconf-northbound-notification { prefix notify-api; revision-date 2015-08-06; }
+ import notification-api { prefix hc-notif-a; revision-date 2016-06-01; }
+ import opendaylight-md-sal-dom { prefix dom; revision-date 2013-10-28;}
+ import opendaylight-sal-binding-broker-impl { prefix binding-impl; revision-date 2013-10-28;}
+
+ description
+ "Module definition for honeycomb notification implementations";
+
+ revision "2016-06-01" {
+ description
+ "Initial revision";
+ }
+
+ identity honeycomb-notification-manager {
+ base config:module-type;
+ config:java-name-prefix HoneycombNotificationManager;
+ config:provided-service hc-notif-a:honeycomb-notification-collector;
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case honeycomb-notification-manager {
+ when "/config:modules/config:module/config:type = 'honeycomb-notification-manager'";
+
+ container runtime-mapping-codec {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity binding-impl:binding-dom-mapping-service;
+ }
+ }
+ }
+
+ container dom-notification-service {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity hc-notif-a:dom-notification-service;
+ }
+ }
+ }
+
+ list notification-producers {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity hc-notif-a:honeycomb-notification-producer;
+ }
+ }
+ }
+
+ }
+ }
+
+ identity honeycomb-dom-notification-service {
+ base config:module-type;
+ config:provided-service hc-notif-a:dom-notification-service;
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case honeycomb-dom-notification-service {
+ when "/config:modules/config:module/config:type = 'honeycomb-dom-notification-service'";
+
+ leaf queue-depth {
+ type uint16;
+ description "Size of the queue for outgoing notifications";
+ }
+ }
+ }
+
+ identity honeycomb-notification-to-netconf-translator {
+ base config:module-type;
+ config:java-name-prefix HoneycombNotificationToNetconfTranslator;
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case honeycomb-notification-to-netconf-translator {
+ when "/config:modules/config:module/config:type = 'honeycomb-notification-to-netconf-translator'";
+
+ container netconf-notification-collector {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity notify-api:netconf-notification-collector;
+ }
+ }
+ }
+ container honeycomb-notification-collector {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity hc-notif-a:honeycomb-notification-collector;
+ }
+ }
+ }
+ container netconf-notification-registry {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity notify-api:netconf-notification-registry;
+ }
+ }
+ }
+ container schema-service {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity dom:schema-service;
+ }
+ }
+ }
+ container dom-notification-service {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity hc-notif-a:dom-notification-service;
+ }
+ }
+ }
+
+ leaf netconf-stream-name {
+ type string;
+ mandatory true;
+ description "Name of the stream under which all the registered notifications should be emitted";
+ }
+
+ leaf netconf-stream-description {
+ type string;
+ mandatory true;
+ description "Description for the stream under which all the registered notifications should be emitted";
+ }
+
+ }
+ }
+
+}
diff --git a/infra/notification/impl/src/test/java/io/fd/honeycomb/v3po/notification/impl/HoneycombNotificationCollectorTest.java b/infra/notification/impl/src/test/java/io/fd/honeycomb/v3po/notification/impl/HoneycombNotificationCollectorTest.java
new file mode 100644
index 0000000..f55d3ab
--- /dev/null
+++ b/infra/notification/impl/src/test/java/io/fd/honeycomb/v3po/notification/impl/HoneycombNotificationCollectorTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.fd.honeycomb.v3po.notification.impl;
+
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.verify;
+
+import com.google.common.collect.Lists;
+import io.fd.honeycomb.v3po.notification.ManagedNotificationProducer;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfSessionStart;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfSessionStartBuilder;
+
+public class HoneycombNotificationCollectorTest {
+
+ private NotificationProducerRegistry notificationRegistry;
+ @Mock
+ private NotificationPublishService notificationService;
+ @Mock
+ private ManagedNotificationProducer producer;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ notificationRegistry = new NotificationProducerRegistry(Lists.newArrayList(producer));
+ }
+
+ @Test
+ public void testNotificationTypes() throws Exception {
+ final HoneycombNotificationCollector honeycombNotificationCollector =
+ new HoneycombNotificationCollector(notificationService, notificationRegistry);
+
+ honeycombNotificationCollector.getNotificationTypes();
+ verify(producer, atLeast(1)).getNotificationTypes();
+ }
+
+ @Test
+ public void testCollect() throws Exception {
+ final HoneycombNotificationCollector honeycombNotificationCollector =
+ new HoneycombNotificationCollector(notificationService, notificationRegistry);
+
+ final NetconfSessionStart notif = new NetconfSessionStartBuilder().build();
+ honeycombNotificationCollector.onNotification(notif);
+ verify(notificationService).putNotification(notif);
+ }
+} \ No newline at end of file
diff --git a/infra/notification/impl/src/test/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerRegistryTest.java b/infra/notification/impl/src/test/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerRegistryTest.java
new file mode 100644
index 0000000..5fdf502
--- /dev/null
+++ b/infra/notification/impl/src/test/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerRegistryTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.fd.honeycomb.v3po.notification.impl;
+
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.hamcrest.CoreMatchers.is;
+import static org.mockito.Mockito.doReturn;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
+import io.fd.honeycomb.v3po.notification.ManagedNotificationProducer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfCapabilityChange;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfSessionEnd;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfSessionStart;
+import org.opendaylight.yangtools.yang.binding.Notification;
+import org.opendaylight.yangtools.yang.common.QName;
+
+public class NotificationProducerRegistryTest {
+
+ @Mock
+ private ManagedNotificationProducer producer;
+ @Mock
+ private ManagedNotificationProducer producer2;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ doReturn(Collections.singleton(NetconfCapabilityChange.class))
+ .when(producer).getNotificationTypes();
+ final ArrayList<Object> producer2Notifications = Lists.newArrayList();
+ producer2Notifications.add(NetconfSessionStart.class);
+ producer2Notifications.add(NetconfSessionEnd.class);
+ doReturn(producer2Notifications).when(producer2).getNotificationTypes();
+ }
+
+ @Test
+ public void testNotificationTypes() throws Exception {
+ final NotificationProducerRegistry notificationRegistry =
+ new NotificationProducerRegistry(Lists.newArrayList(producer, producer2));
+
+ final Set<Class<? extends Notification>> notificationTypes =
+ notificationRegistry.getNotificationTypes();
+
+ Assert.assertThat(notificationTypes, hasItem(NetconfSessionEnd.class));
+ Assert.assertThat(notificationTypes, hasItem(NetconfSessionStart.class));
+ Assert.assertThat(notificationTypes, hasItem(NetconfCapabilityChange.class));
+ }
+
+ @Test
+ public void testNotificationTypesMapped() throws Exception {
+ final NotificationProducerRegistry notificationRegistry =
+ new NotificationProducerRegistry(Lists.newArrayList(producer, producer2));
+
+ final Multimap<ManagedNotificationProducer, QName> notificationTypes =
+ notificationRegistry.getNotificationProducerQNames();
+
+ Assert.assertThat(notificationTypes.keySet(), hasItem(producer));
+ Assert.assertThat(notificationTypes.get(producer), hasItem(NetconfCapabilityChange.QNAME));
+ Assert.assertThat(notificationTypes.keySet(), hasItem(producer2));
+ Assert.assertThat(notificationTypes.get(producer2), hasItem(NetconfSessionStart.QNAME));
+ Assert.assertThat(notificationTypes.get(producer2), hasItem(NetconfSessionEnd.QNAME));
+
+ final Map<QName, ManagedNotificationProducer> notificationQNameToProducer =
+ notificationRegistry.getNotificationQNameToProducer();
+
+ Assert.assertThat(notificationQNameToProducer.keySet(), hasItem(NetconfCapabilityChange.QNAME));
+ Assert.assertThat(notificationQNameToProducer.get(NetconfCapabilityChange.QNAME), is(producer));
+
+ Assert.assertThat(notificationQNameToProducer.keySet(), hasItem(NetconfSessionStart.QNAME));
+ Assert.assertThat(notificationQNameToProducer.keySet(), hasItem(NetconfSessionEnd.QNAME));
+ Assert.assertThat(notificationQNameToProducer.get(NetconfSessionStart.QNAME), is(producer2));
+ Assert.assertThat(notificationQNameToProducer.get(NetconfSessionEnd.QNAME), is(producer2));
+
+
+ }
+} \ No newline at end of file
diff --git a/infra/notification/impl/src/test/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerTrackerTest.java b/infra/notification/impl/src/test/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerTrackerTest.java
new file mode 100644
index 0000000..b62bf07
--- /dev/null
+++ b/infra/notification/impl/src/test/java/io/fd/honeycomb/v3po/notification/impl/NotificationProducerTrackerTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.fd.honeycomb.v3po.notification.impl;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import io.fd.honeycomb.v3po.notification.ManagedNotificationProducer;
+import io.fd.honeycomb.v3po.notification.NotificationCollector;
+import java.util.Collections;
+import java.util.Set;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.md.sal.dom.spi.DOMNotificationSubscriptionListenerRegistry;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfSessionStart;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+public class NotificationProducerTrackerTest {
+
+ private NotificationProducerRegistry registry;
+ @Mock
+ private DOMNotificationSubscriptionListenerRegistry subscriptionRegistry;
+ @Mock
+ private NotificationCollector collector;
+ @Mock
+ private ManagedNotificationProducer producer;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ doReturn(Collections.singleton(NetconfSessionStart.class)).when(producer).getNotificationTypes();
+ registry = new NotificationProducerRegistry(Lists.newArrayList(producer));
+ }
+
+ @Test
+ public void name() throws Exception {
+ final NotificationProducerTracker notificationProducerTracker =
+ new NotificationProducerTracker(registry, collector, subscriptionRegistry);
+ verify(subscriptionRegistry).registerSubscriptionListener(notificationProducerTracker);
+
+ final Set<SchemaPath> subscriptions = Sets.newHashSet();
+ subscriptions.add(SchemaPath.create(true, NetconfSessionStart.QNAME));
+ notificationProducerTracker.onSubscriptionChanged(subscriptions);
+
+ verify(producer).start(collector);
+
+ notificationProducerTracker.onSubscriptionChanged(Sets.newHashSet());
+ verify(producer).stop();
+ }
+} \ No newline at end of file
diff --git a/infra/notification/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/NoetificationToNetconfModuleTest.java b/infra/notification/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/NoetificationToNetconfModuleTest.java
new file mode 100644
index 0000000..ccfb4bb
--- /dev/null
+++ b/infra/notification/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/notification/impl/rev160601/NoetificationToNetconfModuleTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.notification.impl.rev160601;
+
+import javax.annotation.Nonnull;
+import org.hamcrest.CoreMatchers;
+import org.junit.Assert;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
+import org.opendaylight.netconf.notifications.NetconfNotification;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.*;
+import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
+import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+public class NoetificationToNetconfModuleTest {
+
+ private final DOMNotification notification = new DOMNotification() {
+
+ private QName qname = NetconfSessionStart.QNAME;
+ private YangInstanceIdentifier.NodeIdentifier nodeIdentifier =
+ new YangInstanceIdentifier.NodeIdentifier(NetconfSessionStart.QNAME);
+
+ @Nonnull
+ @Override
+ public SchemaPath getType() {
+ return SchemaPath.create(true, qname);
+ }
+
+ @Nonnull
+ @Override
+ public ContainerNode getBody() {
+ return Builders.containerBuilder()
+ .withNodeIdentifier(nodeIdentifier)
+ .withChild(ImmutableNodes.leafNode(QName.create(qname, "username"), "user"))
+ .withChild(ImmutableNodes.leafNode(QName.create(qname, "session-id"), 1))
+ .withChild(ImmutableNodes.leafNode(QName.create(qname, "source-host"), "127.0.0.1"))
+ .build();
+ }
+ };
+
+ @Test
+ public void notificationToXml() throws Exception {
+ final ModuleInfoBackedContext moduleInfoBackedContext = getModuleInfoBackedCOntext();
+
+ final NetconfNotification netconfNotification = HoneycombNotificationToNetconfTranslatorModule
+ .notificationToXml(notification, moduleInfoBackedContext.getSchemaContext());
+
+ final String notificationString = netconfNotification.toString();
+ Assert.assertThat(notificationString, CoreMatchers.containsString("<netconf-session-start"));
+ Assert.assertThat(notificationString, CoreMatchers.containsString("<username>user</username>"));
+ Assert.assertThat(notificationString, CoreMatchers.containsString("eventTime"));
+ }
+
+ private static ModuleInfoBackedContext getModuleInfoBackedCOntext() {
+ final ModuleInfoBackedContext moduleInfoBackedContext = ModuleInfoBackedContext.create();
+ final YangModuleInfo ietfNetconfNotifModuleInfo =
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.$YangModuleInfoImpl
+ .getInstance();
+ moduleInfoBackedContext.registerModuleInfo(ietfNetconfNotifModuleInfo);
+ return moduleInfoBackedContext;
+ }
+} \ No newline at end of file
diff --git a/infra/notification/pom.xml b/infra/notification/pom.xml
new file mode 100644
index 0000000..81b8aae
--- /dev/null
+++ b/infra/notification/pom.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<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">
+
+ <parent>
+ <groupId>org.opendaylight.odlparent</groupId>
+ <artifactId>odlparent</artifactId>
+ <version>1.6.2-Beryllium-SR2</version>
+ <relativePath/>
+ </parent>
+
+ <artifactId>notification-aggregator</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <name>notification</name>
+ <packaging>pom</packaging>
+ <modelVersion>4.0.0</modelVersion>
+ <prerequisites>
+ <maven>3.1.1</maven>
+ </prerequisites>
+ <modules>
+ <module>api</module>
+ <module>impl</module>
+ </modules>
+ <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-install-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/infra/pom.xml b/infra/pom.xml
new file mode 100644
index 0000000..872b749
--- /dev/null
+++ b/infra/pom.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<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">
+
+ <parent>
+ <groupId>org.opendaylight.odlparent</groupId>
+ <artifactId>odlparent</artifactId>
+ <version>1.6.2-Beryllium-SR2</version>
+ <relativePath/>
+ </parent>
+
+ <groupId>io.fd.honeycomb</groupId>
+ <artifactId>infra-aggregator</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <name>honeycomb-infra</name>
+ <packaging>pom</packaging>
+ <modelVersion>4.0.0</modelVersion>
+ <prerequisites>
+ <maven>3.1.1</maven>
+ </prerequisites>
+ <modules>
+ <module>data-api</module>
+ <module>data-impl</module>
+ <module>translate-spi</module>
+ <module>translate-api</module>
+ <module>translate-impl</module>
+ <module>translate-utils</module>
+ <module>notification</module>
+ <module>cfg-init</module>
+ <module>impl</module>
+ <module>karaf</module>
+ <module>features</module>
+ <module>artifacts</module>
+ <module>it</module>
+ </modules>
+ <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-install-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/infra/postman_rest_collection.json b/infra/postman_rest_collection.json
new file mode 100644
index 0000000..3adf195
--- /dev/null
+++ b/infra/postman_rest_collection.json
@@ -0,0 +1,1386 @@
+{
+ "id": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "name": "Honeycomb RESTCONF calls",
+ "description": "Common mgmt operations on VPP using Honeycomb REST interface",
+ "order": [
+ "286f2d2d-88eb-ad68-7c6f-43caecc6073e",
+ "d27322b8-59d5-a2dc-a7a2-8f7197057164",
+ "5dc1d9f4-e7ae-bb21-e558-8a56ac825922",
+ "2f1d8e0d-4961-4b7f-50ad-0210e52e59aa",
+ "93022e97-24fa-5784-1e59-94674817215f",
+ "8b867c90-459f-68f6-4b2e-fa653098c28d",
+ "e611d23a-c205-192b-e8f9-dd99fa169274",
+ "3fccc4cd-f14b-0333-83d5-924afe3938e4"
+ ],
+ "folders": [
+ {
+ "id": "7a914134-23ea-3154-1557-d29dc8d464e7",
+ "name": "IP",
+ "description": "",
+ "order": [
+ "014dcd2b-1024-37a3-bc85-c18b0fdc0e8c",
+ "eb4852a6-ff3a-f9f4-4332-6677a93fcd2a",
+ "dc22d351-497a-4f01-52c1-6f01c76cf80b",
+ "69a05849-026d-f120-5c6a-f3e2b0884d88",
+ "b10169c2-ae0e-bb1c-3dea-ca06839c6c9c",
+ "8d49cf41-facc-c4ac-cee7-475d50e2a0be",
+ "70835949-7252-a3cc-491b-f8aa69286399",
+ "d5a90cfd-fd7e-63b6-e1f1-16fc0671b0e1",
+ "3f7ee49b-ae11-b032-915f-a14bf838246f",
+ "345ba26c-60cf-5fa1-37d0-f5af7a8c33bf"
+ ],
+ "owner": "45557"
+ },
+ {
+ "id": "3d67940d-3c7a-8127-3965-6aee160e6b6f",
+ "name": "L2 FIB",
+ "description": "",
+ "order": [
+ "76e9ee89-1594-ff38-ffff-ffc8de5d4054",
+ "dfbcc9e8-6f3d-b1c2-8bf6-989b1b1b3196",
+ "e2ff4db0-c013-cf89-d7b5-66de22bc7115",
+ "a937f1fc-10d5-bc19-ad5f-ac91fc007779",
+ "cf177689-9dd7-bcfe-d490-e9de6bde4dbb",
+ "0b63013d-3958-b427-2288-380019800468",
+ "99674f70-ec54-99f2-9300-545a031d5bab",
+ "f624bc96-502b-685c-1596-672ad5fcf6a9",
+ "0a1d6c0d-fe5e-1e1d-2471-96d7a4683e2f",
+ "d752fed9-127a-9289-71f3-90ba2b459d77",
+ "5c800144-cf89-7b77-1dd2-f488101ca441"
+ ],
+ "owner": "45557",
+ "collectionId": "e9ba4e80-fb4d-1eae-07e7-97b323164130"
+ },
+ {
+ "id": "f91a6422-9724-e504-a94c-c5a953315b6f",
+ "name": "ACL",
+ "description": "",
+ "order": [
+ "d7cb3d97-fc40-f471-33f3-07aad557777d",
+ "c067f721-6b1c-f205-799d-720b242f8592",
+ "5ab03c5f-03c5-8d42-bf65-024239049857",
+ "4f11c937-9562-3377-d03b-a9829b25f688",
+ "491ee2b7-88bf-3a71-282d-a16a62996026",
+ "fa63c194-ea7a-51ad-a6d8-d7485ed67f2e",
+ "b9931024-fa86-4e04-e2a4-4feeaa9e99e1",
+ "d39e4c39-90b6-072c-44b8-d909cac53a5b",
+ "2ce36b98-d7a9-fe37-80f6-f3a4abf25103",
+ "d0984799-d321-d1e0-a855-cc434519bef0",
+ "be223323-bf59-9c4f-f896-ff74c03b01a1",
+ "ee11f1c0-a1fe-51a6-a5e5-fcdcfc2b620a"
+ ],
+ "owner": "45557",
+ "collectionId": "e9ba4e80-fb4d-1eae-07e7-97b323164130"
+ },
+ {
+ "id": "60596aab-a4f1-bb64-d701-816de9482201",
+ "name": "TAP",
+ "description": "",
+ "order": [
+ "3f9588e4-885f-3792-bdf4-d0f10704ae4d",
+ "27106942-aff5-6ab5-07ae-5315135297a1",
+ "4db9b360-0d57-6ce6-7e3c-a6acfe17d512",
+ "5995dcf7-51c0-42ef-448b-a70bb68735d5"
+ ],
+ "owner": "45557"
+ },
+ {
+ "id": "c97b9ad9-64e6-5de3-09b8-851c1189d767",
+ "name": "VHOST",
+ "description": "",
+ "order": [
+ "7f312f15-a81e-b513-83b7-a5f7755eae67",
+ "ac161bec-e046-4bb7-d695-60bdfb0c6cea",
+ "55102dbd-1fc9-5f91-2082-40a2dc311f4f"
+ ],
+ "owner": "45557"
+ },
+ {
+ "id": "37fd9569-06e3-1f08-fbcc-4b1462107a32",
+ "name": "VLAN",
+ "description": "",
+ "order": [
+ "2ca639f4-f4a4-07c7-9419-79fd66061458",
+ "27eb70b8-a191-dd5c-f106-6693086ce872",
+ "f2e9a3cb-f3cc-f501-6015-8ebf7d8b2c3e",
+ "cbb77318-52e0-5647-cd1c-8c679ea7b830",
+ "8b339568-b60a-715f-d4fd-416bafe981a9",
+ "bd2897c6-5fc7-bec5-87be-4fd52bb8e471",
+ "44de3eff-ace5-90a9-dd16-af3f5f13daad",
+ "b08a0677-6b59-74ea-e5c6-7383194b19dd"
+ ],
+ "owner": "45557",
+ "collectionId": "e9ba4e80-fb4d-1eae-07e7-97b323164130"
+ },
+ {
+ "id": "288569d0-e425-7877-4fd9-a82e8a340ade",
+ "name": "VXLAN-GPE-TUNNEL",
+ "description": "",
+ "order": [
+ "0f223706-ca7f-fb8f-60ed-2b18e769e344",
+ "203ea32c-e43a-669c-4f28-232926df6928"
+ ],
+ "owner": "45557"
+ },
+ {
+ "id": "3868e66d-0ee5-bd4d-6b35-075c4841b5c1",
+ "name": "VXLAN-TUNNEL",
+ "description": "",
+ "order": [
+ "f014ab21-8e40-c344-a68b-0f1b86578bd8",
+ "4f15d0e9-8530-157e-0fe8-d24034bc31df"
+ ],
+ "owner": "45557"
+ }
+ ],
+ "timestamp": 1460119141419,
+ "owner": "45557",
+ "remoteLink": "",
+ "public": false,
+ "requests": [
+ {
+ "id": "0f223706-ca7f-fb8f-60ed-2b18e769e344",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/vxlanGpeTun3",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1464768006369,
+ "name": "Add vxlan-gpe - cfg",
+ "description": "",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"vxlanGpeTun3\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"v3po:vxlan-gpe-tunnel\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"routing\" : {\r\n \"vrf-id\" : \"0\"\r\n },\r\n \"vxlan-gpe\" : {\r\n \"local\" : \"192.168.50.76\",\r\n \"remote\" : \"192.168.50.71\",\r\n \"vni\" : \"9\",\r\n \"next-protocol\" : \"ethernet\",\r\n \"encap-vrf-id\" : \"0\",\r\n \"decap-vrf-id\" : \"0\"\r\n }\r\n }\r\n ]\r\n \r\n}",
+ "folder": "288569d0-e425-7877-4fd9-a82e8a340ade"
+ },
+ {
+ "id": "203ea32c-e43a-669c-4f28-232926df6928",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/vxlanGpeTun3",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "DELETE",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1464764638498,
+ "name": "Delete vxlan-gpe - cfg",
+ "description": "",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "rawModeData": "",
+ "folder": "288569d0-e425-7877-4fd9-a82e8a340ade"
+ },
+ {
+ "id": "27106942-aff5-6ab5-07ae-5315135297a1",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/tapp2",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1462796722186,
+ "name": "Add complex tap ifc - cfg",
+ "description": "",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"tapp2\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"v3po:tap\",\r\n \"tap\" :{\r\n \"tap-name\" : \"tapp2\",\r\n \"mac\" : \"00:ff:ff:ff:ff:ff\",\r\n \"device-instance\" : 55\r\n }\r\n }\r\n ]\r\n \r\n}",
+ "folder": "60596aab-a4f1-bb64-d701-816de9482201"
+ },
+ {
+ "id": "27eb70b8-a191-dd5c-f106-6693086ce872",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F9%2F0",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1464804325716,
+ "name": "Enable GigabitEthernet0/9/0 interface - cfg",
+ "description": "Enables GigabitEthernet0/9/0 interface. Equivalent vppctl command:\n\nvppctl set in state GigabitEthernet0/9/0 up\n\nNeeded to enable sub interface.\n\nTo verify invoke:\n\nvppctl show int",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "folder": "37fd9569-06e3-1f08-fbcc-4b1462107a32",
+ "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"GigabitEthernet0/9/0\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"v3po:ethernet\": {\r\n \"mtu\": 9216\r\n },\r\n \"enabled\": true,\r\n \"vpp-vlan:sub-interfaces\": {\r\n \"sub-interface\": [\r\n {\r\n \"identifier\": 1,\r\n \"vlan-type\": \"802dot1q\",\r\n \"tags\": {\r\n \"tag\": [\r\n {\r\n \"index\": 1,\r\n \"dot1q-tag\": {\r\n \"tag-type\": \"dot1q-types:c-vlan\",\r\n \"vlan-id\": \"any\"\r\n }\r\n },\r\n {\r\n \"index\": 0,\r\n \"dot1q-tag\": {\r\n \"tag-type\": \"dot1q-types:s-vlan\",\r\n \"vlan-id\": \"100\"\r\n }\r\n }\r\n ]\r\n },\r\n \"match\": {\r\n \"vlan-tagged\": {\r\n \"match-exact-tags\": true\r\n }\r\n },\r\n \"enabled\": false\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}"
+ },
+ {
+ "id": "286f2d2d-88eb-ad68-7c6f-43caecc6073e",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "GET",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1460539962712,
+ "name": "List ifcs - cfg",
+ "description": "List ifcs - cfg",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}"
+ },
+ {
+ "id": "014dcd2b-1024-37a3-bc85-c18b0fdc0e8c",
+ "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F8%2F0/ipv4/neighbor/172.16.0.2",
+ "preRequestScript": null,
+ "pathVariables": {},
+ "method": "GET",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": null,
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1466498440466,
+ "name": "Ip Neighbour Get",
+ "description": "This call returns data stored in honeycomb,to verify actual data stored by vpp, call vppctl show ip fib|arp",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "rawModeData": "{\n \n \"interface\":{\n \"name\":\"GigabitEthernet0/8/0\",\n \"type\": \"iana-if-type:ethernetCsmacd\",\n \"enabled\":\"true\",\n \"ipv4\":{\n \"neighbor\":{\n \"ip\":\"172.16.0.2\",\n \"link-layer-address\":\"00:01:11:00:02:02\"\n }\n }\n }\n}\n"
+ },
+ {
+ "id": "dc22d351-497a-4f01-52c1-6f01c76cf80b",
+ "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F8%2F0/ipv4/neighbor/172.16.0.2",
+ "preRequestScript": null,
+ "pathVariables": {},
+ "method": "DELETE",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": null,
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1466498502212,
+ "name": "Ip Neighbour Delete",
+ "description": "Verify this call by invoking vppctl show ip fib|arp",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "rawModeData": "{\n \"neighbor\":{\n \"ip\":\"172.16.0.2\",\n \"link-layer-address\":\"00:01:11:00:02:02\"\n }\n}\n"
+ },
+ {
+ "id": "eb4852a6-ff3a-f9f4-4332-6677a93fcd2a",
+ "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F8%2F0/ipv4/neighbor/172.16.0.2",
+ "preRequestScript": null,
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": null,
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1466498409820,
+ "name": "Ip Neighbour Add",
+ "description": "This call doesnt have respective dump call,because of performance issues(dump for this can contain millions of entries). Data inserted throught this call can be verified by calling vppctl show ip fib|arp",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "rawModeData": "{\n \n \"neighbor\":{\n \"ip\":\"172.16.0.2\",\n \"link-layer-address\":\"00:01:11:00:02:02\"\n }\n \n}\n"
+ },
+ {
+ "id": "2ca639f4-f4a4-07c7-9419-79fd66061458",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F9%2F0/vpp-vlan:sub-interfaces/sub-interface/1",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1464804304987,
+ "name": "Add sub interface - cfg",
+ "description": "Adds sub interface. Corresponsing vpp cli command:\n\nvppctl create sub GigabitEthernet0/9/0 1 dot1q 100 inner-dot1q any\n\nTo verify run:\n./build-root/install-vpp-native/vpp-api-test/bin/vpp_api_test json\nand invoke:\n\n#vat sw_interface_dump",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "folder": "37fd9569-06e3-1f08-fbcc-4b1462107a32",
+ "rawModeData": "{\r\n \"sub-interface\": [\r\n {\r\n \"identifier\": \"1\",\r\n \"vlan-type\": \"802dot1q\",\r\n \"tags\": {\r\n \"tag\": [\r\n {\r\n \"index\": \"0\",\r\n \"dot1q-tag\": {\r\n \"tag-type\": \"dot1q-types:s-vlan\",\r\n \"vlan-id\": \"100\"\r\n }\r\n },\r\n {\r\n \"index\": \"1\",\r\n \"dot1q-tag\": {\r\n \"tag-type\": \"dot1q-types:c-vlan\",\r\n \"vlan-id\": \"any\"\r\n }\r\n }\r\n ]\r\n },\r\n \"match\": {\r\n \"vlan-tagged\": {\r\n \"match-exact-tags\": \"true\"\r\n }\r\n },\r\n \"enabled\": \"false\"\r\n }\r\n ]\r\n}"
+ },
+ {
+ "id": "2f1d8e0d-4961-4b7f-50ad-0210e52e59aa",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/v3po:vpp",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "GET",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1460540006597,
+ "name": "Read vpp - cfg",
+ "description": "",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}"
+ },
+ {
+ "id": "76e9ee89-1594-ff38-ffff-ffc8de5d4054",
+ "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+ "url": "http://localhost:8181/restconf/config/v3po:vpp/bridge-domains/bridge-domain/testBD",
+ "pathVariables": {},
+ "preRequestScript": "",
+ "method": "PUT",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "data": [],
+ "dataMode": "raw",
+ "name": "Create bridge domain - cfg",
+ "description": "Creates bridgfe domain. Corresponds to invoking:\n\nvat# bridge_domain_add_del bd_id [bd_id] learn 0 forward 0 uu-flood 0 flood 1 arp-term 0\n\nTo verify run:\n\nvppctl show bridge-domain [bd_id] detail",
+ "descriptionFormat": "html",
+ "time": 1465805138795,
+ "version": 2,
+ "responses": [],
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "folder": "3d67940d-3c7a-8127-3965-6aee160e6b6f",
+ "rawModeData": "{\r\n \"bridge-domain\": [\r\n {\r\n \"name\": \"testBD\",\r\n \"flood\": \"true\",\r\n \"forward\": \"false\",\r\n \"learn\": \"false\",\r\n \"unknown-unicast-flood\": \"false\",\r\n \"arp-termination\": \"false\"\r\n }\r\n ]\r\n}"
+ },
+ {
+ "id": "dfbcc9e8-6f3d-b1c2-8bf6-989b1b1b3196",
+ "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+ "url": "http://localhost:8181/restconf/config/v3po:vpp/bridge-domains/bridge-domain/testBD",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "GET",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1465806733493,
+ "name": "Show bridge domain - cfg",
+ "description": "Shows testBD bridge domain configuration.",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "rawModeData": "{\r\n \"bridge-domain\": [\r\n {\r\n \"name\": \"testBD\",\r\n \"flood\": \"true\",\r\n \"forward\": \"false\",\r\n \"learn\": \"false\",\r\n \"unknown-unicast-flood\": \"false\",\r\n \"arp-termination\": \"false\"\r\n }\r\n ]\r\n}"
+ },
+ {
+ "id": "e2ff4db0-c013-cf89-d7b5-66de22bc7115",
+ "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+ "url": "http://localhost:8181/restconf/operational/v3po:vpp-state/bridge-domains/bridge-domain/testBD",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "GET",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1465806752970,
+ "name": "Show bridge domain - oper",
+ "description": "Shows testBD bridge domain operational state.\nCorresponds to invoking:\n\nvppctl show bridge-domain [bd_id] detail",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "rawModeData": "{\r\n \"bridge-domain\": [\r\n {\r\n \"name\": \"testBD\",\r\n \"flood\": \"true\",\r\n \"forward\": \"false\",\r\n \"learn\": \"false\",\r\n \"unknown-unicast-flood\": \"false\",\r\n \"arp-termination\": \"false\"\r\n }\r\n ]\r\n}"
+ },
+ {
+ "id": "a937f1fc-10d5-bc19-ad5f-ac91fc007779",
+ "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/v3po:l2",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1465805545425,
+ "name": "Add local0 to bridge domain",
+ "description": "Adds l2 interconnection of bridge-based type to local0 interface.\nCorresponds to the following command:\n\nvppctl set interface l2 bridge local0 [bd_id]\n\nTo verify invoke:\n\nvppctl show bridge-domain [bd_id] detail",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "rawModeData": "{\r\n \"l2\": {\r\n \"bridge-domain\": \"testBD\",\r\n \"split-horizon-group\": 1,\r\n \"bridged-virtual-interface\": \"false\"\r\n }\r\n}"
+ },
+ {
+ "id": "cf177689-9dd7-bcfe-d490-e9de6bde4dbb",
+ "headers": "",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/",
+ "preRequestScript": null,
+ "pathVariables": {},
+ "method": "GET",
+ "data": null,
+ "dataMode": "params",
+ "tests": null,
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1465805728052,
+ "name": "Show local0 - cfg",
+ "description": "Shows local0 interface configuration",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": []
+ },
+ {
+ "id": "0b63013d-3958-b427-2288-380019800468",
+ "headers": "",
+ "url": "http://localhost:8181/restconf/operational/ietf-interfaces:interfaces-state/interface/local0/",
+ "pathVariables": {},
+ "preRequestScript": null,
+ "method": "GET",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "data": null,
+ "dataMode": "params",
+ "name": "Show local0 - oper",
+ "description": "Shows local0 interface operational state",
+ "descriptionFormat": "html",
+ "time": 1465805719840,
+ "version": 2,
+ "responses": [],
+ "tests": null,
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "folder": "3d67940d-3c7a-8127-3965-6aee160e6b6f"
+ },
+ {
+ "id": "99674f70-ec54-99f2-9300-545a031d5bab",
+ "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+ "url": "http://localhost:8181/restconf/config/v3po:vpp/bridge-domains/bridge-domain/testBD/l2-fib-table/l2-fib-entry/aa:bb:cc:dd:ee:ff",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1465806456783,
+ "name": "Add L2 FIB entry (forward)",
+ "description": "Adds L2 FIB static entry. Corresponds to invoking:\n\nvppctl l2fib add aa:bb:cc:dd:ee:ff [bd_id] local0\n\nTo verify run:\n\nvppctl show l2fib verbose",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "rawModeData": "{\n \"l2-fib-entry\": [\n {\n \"phys-address\": \"aa:bb:cc:dd:ee:ff\",\n \"outgoing-interface\": \"local0\",\n \"action\": \"l2-fib-forward\"\n }\n ]\n}"
+ },
+ {
+ "id": "f624bc96-502b-685c-1596-672ad5fcf6a9",
+ "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+ "url": "http://localhost:8181/restconf/config/v3po:vpp/bridge-domains/bridge-domain/testBD/l2-fib-table/l2-fib-entry/aa:bb:cc:dd:ee:ff",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "DELETE",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1465806577485,
+ "name": "Delete L2 FIB entry",
+ "description": "Removes L2 FIB entry. Corresponds to invoking:\n\nvppctl l2fib del aa:bb:cc:dd:ee:ff [bd_id]\n\nTo verify run:\n\nvppctl show l2fib verbose",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "rawModeData": ""
+ },
+ {
+ "id": "0a1d6c0d-fe5e-1e1d-2471-96d7a4683e2f",
+ "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+ "url": "http://localhost:8181/restconf/config/v3po:vpp/bridge-domains/bridge-domain/testBD/l2-fib-table/l2-fib-entry/11:22:33:44:55:66",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1465806064247,
+ "name": "Add L2 FIB entry (static, forward)",
+ "description": "Adds L2 FIB static entry. Corresponds to invoking:\n\nvppctl l2fib add 11:22:33:44:55:66 [bd_id] local0 static\n\nTo verify run:\n\nvppctl show l2fib verbose",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "rawModeData": "{\n \"l2-fib-entry\": [\n {\n \"phys-address\": \"11:22:33:44:55:66\",\n \"outgoing-interface\": \"local0\",\n \"static-config\": \"true\",\n \"action\": \"l2-fib-forward\"\n }\n ]\n}"
+ },
+ {
+ "id": "d752fed9-127a-9289-71f3-90ba2b459d77",
+ "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+ "url": "http://localhost:8181/restconf/config/v3po:vpp/bridge-domains/bridge-domain/testBD/l2-fib-table/l2-fib-entry/00:01:02:03:04:05",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1465814845273,
+ "name": "Add L2 FIB entry (filter)",
+ "description": "Adds L2 FIB static entry. Corresponds to invoking:\n\nvppctl l2fib add 00:01:02:03:04:05 [bd_id] filter\n\nTo verify run:\n\nvppctl show l2fib verbose",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "rawModeData": "{\n \"l2-fib-entry\": [\n {\n \"phys-address\": \"00:01:02:03:04:05\",\n \"outgoing-interface\": \"local0\",\n \"static-config\": \"true\",\n \"action\": \"l2-fib-filter\"\n }\n ]\n}"
+ },
+ {
+ "id": "5c800144-cf89-7b77-1dd2-f488101ca441",
+ "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/v3po:l2",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "DELETE",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1465984375972,
+ "name": "Remove local0 from bridge domain",
+ "description": "Removes l2 interconnection of bridge-based type from local0 interface.\nCorresponds to the following VAT command:\n\nvat# sw_interface_set_l2_bridge sw_if_index 0 bd_id 1 disable\n\nVerification in VAT:\n\nvat# bridge_domain_dump",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "rawModeData": ""
+ },
+ {
+ "id": "d7cb3d97-fc40-f471-33f3-07aad557777d",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/vpp-classifier:vpp-classifier/",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "GET",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1467377260818,
+ "name": "Get classify tables - cfg",
+ "description": "Shows classify table configuration.",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "folder": "f91a6422-9724-e504-a94c-c5a953315b6f",
+ "rawModeData": ""
+ },
+ {
+ "id": "c067f721-6b1c-f205-799d-720b242f8592",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/operational/vpp-classifier:vpp-classifier-state/",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "GET",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1467377066230,
+ "name": "Get classify tables - oper",
+ "description": "Shows classify tables configured in the VPP.\n\nCorresponds to:\n\nvppctl sh class table verbose",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "folder": "f91a6422-9724-e504-a94c-c5a953315b6f",
+ "rawModeData": ""
+ },
+ {
+ "id": "5ab03c5f-03c5-8d42-bf65-024239049857",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/vpp-classifier:vpp-classifier/classify-table/table0",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1468493354688,
+ "name": "Add classify table0",
+ "description": "Adds classify table0. Corresponding vpp cli command:\n\nvppctl classify table mask l2 src\n\nTo verify invoke:\n\nvppctl sh class table verbose\n\nor:\n\nvat# classify_table_info table_id 0",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "folder": "f91a6422-9724-e504-a94c-c5a953315b6f",
+ "rawModeData": "{\n \"classify-table\": [\n {\n \"name\": \"table0\",\n \"nbuckets\": \"2\",\n \"memory_size\": \"1048576\",\n \"miss_next\": \"permit\",\n \"mask\": \"00:00:00:00:00:00:ff:ff:ff:ff:ff:ff:00:00:00:00\"\n }\n ]\n}"
+ },
+ {
+ "id": "4f11c937-9562-3377-d03b-a9829b25f688",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/operational/vpp-classifier:vpp-classifier-state/classify-table/table0",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "GET",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1467378420028,
+ "name": "Get classify table - oper",
+ "description": "Shows classify table 0 operational state.\n\nCorresponds to:\n\nvat# classify_table_info table_id 0",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "folder": "f91a6422-9724-e504-a94c-c5a953315b6f",
+ "rawModeData": ""
+ },
+ {
+ "id": "491ee2b7-88bf-3a71-282d-a16a62996026",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/vpp-classifier:vpp-classifier/classify-table/table1",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1468493298160,
+ "name": "Add classify table1",
+ "description": "Adds classify table1 chained to classify table0.\n\nCorresponding vpp cli command:\n\nvppctl classify table mask l2 dst next-table 0\n\nTo verify invoke:\n\nvppctl sh class table verbose\n\nor:\n\nvat# classify_table_info table_id 1",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "folder": "f91a6422-9724-e504-a94c-c5a953315b6f",
+ "rawModeData": "{\n \"classify-table\": [\n {\n \"name\": \"table1\",\n \"next_table\": \"table0\",\n \"nbuckets\": \"2\",\n \"memory_size\": \"1048576\",\n \"miss_next\": \"permit\",\n \"mask\": \"ff:ff:ff:ff:ff:ff:00:00:00:00:00:00:00:00:00:00\"\n }\n ]\n}"
+ },
+ {
+ "id": "fa63c194-ea7a-51ad-a6d8-d7485ed67f2e",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/vpp-classifier:vpp-classifier/classify-table/table0/classify-session/00:00:00:00:00:00:01:02:03:04:05:06:00:00:00:00",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1468493546163,
+ "name": "Add classify session",
+ "description": "Adds classify session to table0. Corresponding vpp cli command:\n\nvppctl classify session acl-hit-next deny opaque-index 0 table-index 0 match l2 src 01:02:03:04:05:06\n\nTo verify invoke:\n\nvppctl sh class table verbose",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "folder": "f91a6422-9724-e504-a94c-c5a953315b6f",
+ "rawModeData": "{\n \"classify-session\": [\n {\n \"hit_next\": \"deny\",\n \"match\": \"00:00:00:00:00:00:01:02:03:04:05:06:00:00:00:00\"\n }\n ]\n}"
+ },
+ {
+ "id": "b9931024-fa86-4e04-e2a4-4feeaa9e99e1",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/vpp-classifier:vpp-classifier/classify-table/table0/classify-session/00:00:00:00:00:00:01:02:03:04:05:07:00:00:00:00",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1468493583927,
+ "name": "Add another classify session",
+ "description": "Adds second classify session to table0. Corresponding vpp cli command:\n\nvppctl classify session acl-hit-next deny opaque-index 0 table-index 0 match l2 src 01:02:03:04:05:07\n\nTo verify invoke:\n\nvppctl sh class table verbose",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "folder": "f91a6422-9724-e504-a94c-c5a953315b6f",
+ "rawModeData": "{\n \"classify-session\": [\n {\n \"hit_next\": \"deny\",\n \"match\": \"00:00:00:00:00:00:01:02:03:04:05:07:00:00:00:00\"\n }\n ]\n}"
+ },
+ {
+ "id": "d39e4c39-90b6-072c-44b8-d909cac53a5b",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/v3po:acl",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1468495690154,
+ "name": "Enable L2 and Ipv4 ACL on local0 interface",
+ "description": "Enables L2 and Ipv4 ACL on local0. Corresponding vpp cli commands:\n\nset int input acl intfc local0 l2-table 0\n\nset int input acl intfc local0 ip4-table 0\n\nTo verify invoke:\n\nvppctl show inacl type l2\n\nthen:\n\nvppctl show inacl type ip4",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "folder": "f91a6422-9724-e504-a94c-c5a953315b6f",
+ "rawModeData": "{\n \"v3po:acl\": {\n \"l2-acl\": {\n \"classify-table\": \"table0\"\n },\n \"ip4-acl\": {\n \"classify-table\": \"table0\"\n }\n }\n}"
+ },
+ {
+ "id": "2ce36b98-d7a9-fe37-80f6-f3a4abf25103",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/v3po:acl/",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "DELETE",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1467380189765,
+ "name": "Disable ACL on local0 interface",
+ "description": "Disables ACL on local0. To verify invoke:\n\nvppctl show inacl type l2\n\nand:\n\nvppctl show inacl type ip4",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "folder": "f91a6422-9724-e504-a94c-c5a953315b6f",
+ "rawModeData": ""
+ },
+ {
+ "id": "d0984799-d321-d1e0-a855-cc434519bef0",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/vpp-classifier:vpp-classifier/classify-table/table0/classify-session/00:00:00:00:00:00:01:02:03:04:05:06:00:00:00:00",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "DELETE",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1468493934488,
+ "name": "Remove classify session",
+ "description": "Removes classify session. To verify invoke:\n\nvppctl sh class table verbose",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "folder": "f91a6422-9724-e504-a94c-c5a953315b6f",
+ "rawModeData": ""
+ },
+ {
+ "id": "be223323-bf59-9c4f-f896-ff74c03b01a1",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/vpp-classifier:vpp-classifier/classify-table/table0",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "DELETE",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1467377830897,
+ "name": "Remove classify table0",
+ "description": "Removes classify table0. Corresponds to the following command:\n\nvppctl classify table del table 0\n\nTo verify invoke:\n\nvppctl sh class table verbose",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "folder": "f91a6422-9724-e504-a94c-c5a953315b6f",
+ "rawModeData": ""
+ },
+ {
+ "id": "ee11f1c0-a1fe-51a6-a5e5-fcdcfc2b620a",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/vpp-classifier:vpp-classifier/classify-table/table1",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "DELETE",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1467377388428,
+ "name": "Remove classify table1",
+ "description": "Removes classify table1. Corresponds to the following command:\n\nvppctl classify table del table 1\n\nTo verify invoke:\n\nvppctl sh class table verbose",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "folder": "f91a6422-9724-e504-a94c-c5a953315b6f",
+ "rawModeData": ""
+ },
+ {
+ "id": "3f9588e4-885f-3792-bdf4-d0f10704ae4d",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/tapp",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1462535811974,
+ "name": "Add simple tap ifc -cfg",
+ "description": "",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "folder": "60596aab-a4f1-bb64-d701-816de9482201",
+ "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"tapp\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"v3po:tap\",\r\n \"tap\" :{\r\n \"tap-name\" : \"tapp\"\r\n }\r\n }\r\n ]\r\n \r\n}"
+ },
+ {
+ "id": "3fccc4cd-f14b-0333-83d5-924afe3938e4",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1460640004531,
+ "name": "Set vrf id for local0 - cfg",
+ "description": "",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"local0\",\r\n \"description\": \"for testing purposes only\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"routing\" : {\r\n \"vrf-id\" : \"7\"\r\n },\r\n \"v3po:ethernet\": {\r\n \"mtu\": 64\r\n }\r\n }\r\n ]\r\n \r\n}"
+ },
+ {
+ "id": "44de3eff-ace5-90a9-dd16-af3f5f13daad",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F9%2F0/vpp-vlan:sub-interfaces/sub-interface/1/l2/rewrite",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1464805188780,
+ "name": "Enable tag-rewrite translate 1-2 - cfg",
+ "description": "Enables tag-rewrite translate 1-2 operation for GigabitEthernet0/9/0.1 sub-interface. Corresponsing vpp cli command:\n\nvppctl set interface l2 tag-rewrite GigabitEthernet0/9/0.1 translate 1-2 dot1q 111 222\n\nTo verify run:\n./build-root/install-vpp-native/vpp-api-test/bin/vpp_api_test json\nand invoke:\n\n#vat sw_interface_dump\n\nor if sub-interface was added to bridge domain:\n\nvppctl show bridge-domain [bd_id] detail",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "folder": "37fd9569-06e3-1f08-fbcc-4b1462107a32",
+ "rawModeData": "{\r\n \"rewrite\": {\r\n \"vlan-type\": \"vpp-vlan:802dot1q\",\r\n \"pop-tags\": \"1\",\r\n \"push-tags\": [\r\n {\r\n \"index\": 0,\r\n \"dot1q-tag\": {\r\n \"tag-type\": \"dot1q-types:s-vlan\",\r\n \"vlan-id\": 111\r\n }\r\n },\r\n {\r\n \"index\": 1,\r\n \"dot1q-tag\": {\r\n \"tag-type\": \"dot1q-types:c-vlan\",\r\n \"vlan-id\": 222\r\n }\r\n }\r\n ]\r\n }\r\n}"
+ },
+ {
+ "id": "4db9b360-0d57-6ce6-7e3c-a6acfe17d512",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/tapp2",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1462796801468,
+ "name": "Modify complex tap ifc - cfg",
+ "description": "",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"tapp2\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"v3po:tap\",\r\n \"tap\" :{\r\n \"tap-name\" : \"tapp2\",\r\n \"mac\" : \"00:ff:ff:ff:ff:ae\",\r\n \"device-instance\" : 77\r\n }\r\n }\r\n ]\r\n \r\n}",
+ "folder": "60596aab-a4f1-bb64-d701-816de9482201"
+ },
+ {
+ "id": "4f15d0e9-8530-157e-0fe8-d24034bc31df",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/vxlanTun1",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "DELETE",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": "{}",
+ "time": 1462892071867,
+ "name": "Delete virtual ifc - cfg",
+ "description": "",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "folder": "3868e66d-0ee5-bd4d-6b35-075c4841b5c1",
+ "timestamp": null,
+ "rawModeData": ""
+ },
+ {
+ "id": "55102dbd-1fc9-5f91-2082-40a2dc311f4f",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/vhost1",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "DELETE",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": "{}",
+ "time": 1462891488523,
+ "name": "Delete vhost user ifc - cfg",
+ "description": "Deletes vhost user interface.\nCorresponding vpp CLI command:\n\nvppctl delete vhost-user sw_if_index [index]\n\nTo verify invoke:\n\nvppctl show vhost-user\n\nor\n\nvppctl show int",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "folder": "c97b9ad9-64e6-5de3-09b8-851c1189d767",
+ "rawModeData": "",
+ "descriptionFormat": null
+ },
+ {
+ "id": "5995dcf7-51c0-42ef-448b-a70bb68735d5",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/tapp2",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "DELETE",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1462796994090,
+ "name": "Delete complex tap ifc - cfg",
+ "description": "",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "rawModeData": "",
+ "folder": "60596aab-a4f1-bb64-d701-816de9482201"
+ },
+ {
+ "id": "5dc1d9f4-e7ae-bb21-e558-8a56ac825922",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/operational/v3po:vpp-state",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "GET",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1460539994330,
+ "name": "Read vpp-state - oper",
+ "description": "",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}"
+ },
+ {
+ "id": "7f312f15-a81e-b513-83b7-a5f7755eae67",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/vhost1",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1462891472552,
+ "name": "Add vhost user ifc - cfg",
+ "description": "Adds vhost-user interface.\nCorresponsing vpp cli command:\n\ncreate vhost-user socket /tmp/soc1 server\n\nTo verify invoke:\n\nvppctl show vhost-user\n\nor\n\nvppctl show int",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"vhost1\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"v3po:vhost-user\",\r\n \"enabled\": \"true\",\r\n \"vhost-user\" : {\r\n \"socket\": \"/tmp/soc1\",\r\n \"role\": \"server\"\r\n }\r\n }\r\n ]\r\n \r\n}",
+ "folder": "c97b9ad9-64e6-5de3-09b8-851c1189d767"
+ },
+ {
+ "id": "8b339568-b60a-715f-d4fd-416bafe981a9",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F9%2F0/vpp-vlan:sub-interfaces/sub-interface/1/l2/rewrite",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": "{}",
+ "time": 1464803940412,
+ "name": "Enable tag-rewrite push - cfg",
+ "description": "Enables tag-rewrite push operation for GigabitEthernet0/9/0.1 sub-interface. Corresponsing vpp cli command:\n\nvppctl set interface l2 tag-rewrite GigabitEthernet0/9/0.1 push dot1q 123 456\n\nTo verify run:\n./build-root/install-vpp-native/vpp-api-test/bin/vpp_api_test json\nand invoke:\n\n#vat sw_interface_dump\n\nor if sub-interface was added to bridge domain:\n\nvppctl show bridge-domain [bd_id] detail",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "folder": "37fd9569-06e3-1f08-fbcc-4b1462107a32",
+ "timestamp": null,
+ "rawModeData": "{\r\n \"rewrite\": {\r\n \"vlan-type\": \"vpp-vlan:802dot1q\",\r\n \"push-tags\": [\r\n {\r\n \"index\": 0,\r\n \"dot1q-tag\": {\r\n \"tag-type\": \"dot1q-types:s-vlan\",\r\n \"vlan-id\": 123\r\n }\r\n },\r\n {\r\n \"index\": 1,\r\n \"dot1q-tag\": {\r\n \"tag-type\": \"dot1q-types:c-vlan\",\r\n \"vlan-id\": 456\r\n }\r\n }\r\n ]\r\n }\r\n}"
+ },
+ {
+ "id": "8b867c90-459f-68f6-4b2e-fa653098c28d",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1460540047356,
+ "name": "Enable local0 interface - cfg",
+ "description": "",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"local0\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"v3po:ethernet\": {\r\n \"mtu\": 64\r\n }\r\n }\r\n ]\r\n \r\n}"
+ },
+ {
+ "id": "93022e97-24fa-5784-1e59-94674817215f",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/operational/naming-context:contexts",
+ "pathVariables": {},
+ "preRequestScript": "",
+ "method": "GET",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "data": [],
+ "dataMode": "raw",
+ "name": "List naming contexts - context",
+ "description": "List mapping context stored in context datastore",
+ "descriptionFormat": "html",
+ "time": 1463556756647,
+ "version": 2,
+ "responses": [],
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}"
+ },
+ {
+ "id": "69a05849-026d-f120-5c6a-f3e2b0884d88",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/operational/ietf-interfaces:interfaces-state/interface/local0",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "GET",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1465472429324,
+ "name": "Read local0 - oper",
+ "description": "",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "folder": "7a914134-23ea-3154-1557-d29dc8d464e7",
+ "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}"
+ },
+ {
+ "id": "b10169c2-ae0e-bb1c-3dea-ca06839c6c9c",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/ipv4/address/127.0.0.1",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1466496859574,
+ "name": "Set ipv4 local0 interface - cfg",
+ "description": "",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "folder": "7a914134-23ea-3154-1557-d29dc8d464e7",
+ "rawModeData": "{\r\n \"address\": [{\r\n \"ip\" : \"127.0.0.1\",\r\n \"prefix-length\" : \"24\"\r\n }]\r\n}"
+ },
+ {
+ "id": "8d49cf41-facc-c4ac-cee7-475d50e2a0be",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/ipv4/address/127.0.0.1",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "DELETE",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1466497187475,
+ "name": "Remove ipv4 from local0 interface - cfg",
+ "description": "",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "folder": "7a914134-23ea-3154-1557-d29dc8d464e7",
+ "rawModeData": ""
+ },
+ {
+ "id": "70835949-7252-a3cc-491b-f8aa69286399",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/ipv4/address/127.0.0.1",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1466497176571,
+ "name": "Set ipv4 local0 interface - cfg netmask",
+ "description": "",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "folder": "7a914134-23ea-3154-1557-d29dc8d464e7",
+ "rawModeData": "{\r\n \"address\": [{\r\n \"ip\" : \"127.0.0.1\",\r\n \"netmask\": \"255.255.255.128\"\r\n }]\r\n}"
+ },
+ {
+ "id": "d5a90cfd-fd7e-63b6-e1f1-16fc0671b0e1",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/operational/ietf-interfaces:interfaces-state/interface/local0/ipv4",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "GET",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1465473594194,
+ "name": "Read local0/ipv4 - oper",
+ "description": "",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "folder": "7a914134-23ea-3154-1557-d29dc8d464e7",
+ "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}"
+ },
+ {
+ "id": "3f7ee49b-ae11-b032-915f-a14bf838246f",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/ipv4",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "GET",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1466497212835,
+ "name": "Read local0/ipv4 - cfg",
+ "description": "",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "folder": "7a914134-23ea-3154-1557-d29dc8d464e7",
+ "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}"
+ },
+ {
+ "id": "345ba26c-60cf-5fa1-37d0-f5af7a8c33bf",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F9%2F0/vpp-vlan:sub-interfaces/sub-interface/1/ipv4/address/1.2.3.4",
+ "pathVariables": {},
+ "preRequestScript": "",
+ "method": "PUT",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "data": [],
+ "dataMode": "raw",
+ "name": "Set ipv4 for sub-interface - cfg",
+ "description": "Correponds to the following command:\n\nvppctl set interface ip address GigabitEthernet0/9/0.1 1.2.3.4/8\n\nTo verify invoke:\nvppctl show int",
+ "descriptionFormat": "html",
+ "time": 1467117222646,
+ "version": 2,
+ "responses": [],
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "folder": "7a914134-23ea-3154-1557-d29dc8d464e7",
+ "rawModeData": "{\r\n \"address\": [{\r\n \"ip\" : \"1.2.3.4\",\r\n \"prefix-length\" : \"8\"\r\n }]\r\n}"
+ },
+ {
+ "id": "ac161bec-e046-4bb7-d695-60bdfb0c6cea",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/vhost1",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1462891483790,
+ "name": "Modify vhost user ifc - cfg",
+ "description": "Modifies vhost-user interface socket.\nTo verify invoke:\n\nvppctl show vhost-user",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"vhost1\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"v3po:vhost-user\",\r\n \"enabled\": \"true\",\r\n \"vhost-user\" : {\r\n \"socket\": \"/tmp/soc2\",\r\n \"role\": \"server\"\r\n }\r\n }\r\n ]\r\n \r\n}",
+ "folder": "c97b9ad9-64e6-5de3-09b8-851c1189d767"
+ },
+ {
+ "id": "b08a0677-6b59-74ea-e5c6-7383194b19dd",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F9%2F0/vpp-vlan:sub-interfaces/sub-interface/1/l2/rewrite",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "DELETE",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1464804511683,
+ "name": "Disable tag-rewrite - cfg",
+ "description": "Disables tag-rewrite operation for GigabitEthernet0/9/0.1 sub-interface. Corresponsing vpp cli command:\n\nvppctl set interface l2 tag-rewrite GigabitEthernet0/9/0.1 disable\n\nTo verify run:\n./build-root/install-vpp-native/vpp-api-test/bin/vpp_api_test json\nand invoke:\n\n#vat sw_interface_dump\n\nor if sub-interface was added to bridge domain:\n\nvppctl show bridge-domain [bd_id] detail",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "folder": "37fd9569-06e3-1f08-fbcc-4b1462107a32",
+ "rawModeData": ""
+ },
+ {
+ "id": "bd2897c6-5fc7-bec5-87be-4fd52bb8e471",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F9%2F0/vpp-vlan:sub-interfaces/sub-interface/1/l2/rewrite",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1464805111410,
+ "name": "Enable tag-rewrite pop 1 - cfg",
+ "description": "Enables tag-rewrite pop 1 operation for GigabitEthernet0/9/0.1 sub-interface. Corresponsing vpp cli command:\n\nvppctl set interface l2 tag-rewrite GigabitEthernet0/9/0.1 pop 1\n\nTo verify run:\n./build-root/install-vpp-native/vpp-api-test/bin/vpp_api_test json\nand invoke:\n\n#vat sw_interface_dump\n\nor if sub-interface was added to bridge domain:\n\nvppctl show bridge-domain [bd_id] detail",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "folder": "37fd9569-06e3-1f08-fbcc-4b1462107a32",
+ "rawModeData": "{\r\n \"rewrite\": {\r\n \"pop-tags\": \"1\"\r\n }\r\n}"
+ },
+ {
+ "id": "cbb77318-52e0-5647-cd1c-8c679ea7b830",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F9%2F0/vpp-vlan:sub-interfaces/sub-interface/1/l2",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1464813539029,
+ "name": "Add sub interface to bridge-domain",
+ "description": "Adds sub interface to bridge domain. Corresponsing vpp cli command:\n\nvppctl set interface l2 bridge GigabitEthernet0/9/0.1 1 1\n\nTo verify invoke:\nvppctl show bridge-domain 1 detail",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "folder": "37fd9569-06e3-1f08-fbcc-4b1462107a32",
+ "rawModeData": "{\r\n \"l2\": {\r\n \"bridge-domain\": \"testBD\",\r\n \"split-horizon-group\": 1,\r\n \"bridged-virtual-interface\": \"false\"\r\n }\r\n}"
+ },
+ {
+ "id": "d27322b8-59d5-a2dc-a7a2-8f7197057164",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/operational/ietf-interfaces:interfaces-state/",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "GET",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1460539972177,
+ "name": "List ifcs - oper",
+ "description": "",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}"
+ },
+ {
+ "id": "e611d23a-c205-192b-e8f9-dd99fa169274",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1460636113690,
+ "name": "Set interfaces bulk edit - cfg",
+ "description": "",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "rawModeData": "{\n \"interfaces\": {\n \"interface\": [\n {\n \"name\": \"pg/stream-2\",\n \"enabled\": true,\n \"type\": \"iana-if-type:ethernetCsmacd\"\n },\n {\n \"name\": \"pg/stream-3\",\n \"enabled\": true,\n \"type\": \"iana-if-type:ethernetCsmacd\"\n },\n {\n \"name\": \"pg/stream-0\",\n \"enabled\": true,\n \"type\": \"iana-if-type:ethernetCsmacd\"\n },\n {\n \"name\": \"local0\",\n \"description\": \"for testing purposes\",\n \"type\": \"iana-if-type:ethernetCsmacd\",\n \"enabled\": true\n },\n {\n \"name\": \"pg/stream-1\",\n \"enabled\": true,\n \"type\": \"iana-if-type:ethernetCsmacd\"\n }\n ]\n }\n}"
+ },
+ {
+ "id": "f014ab21-8e40-c344-a68b-0f1b86578bd8",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/vxlanTun1",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1464767860505,
+ "name": "Add virtual ifc - cfg",
+ "description": "",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"vxlanTun1\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"v3po:vxlan-tunnel\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"routing\" : {\r\n \"vrf-id\" : \"0\"\r\n },\r\n \"vxlan\" : {\r\n \"src\" : \"192.168.1.6\",\r\n \"dst\" : \"192.168.1.9\",\r\n \"vni\" : \"88\",\r\n \"encap-vrf-id\" : \"0\"\r\n }\r\n }\r\n ]\r\n \r\n}",
+ "folder": "3868e66d-0ee5-bd4d-6b35-075c4841b5c1"
+ },
+ {
+ "id": "f2e9a3cb-f3cc-f501-6015-8ebf7d8b2c3e",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/GigabitEthernet0%2F9%2F0/vpp-vlan:sub-interfaces/sub-interface/1",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1464804333865,
+ "name": "Enable GigabitEthernet0/9/0.1 interface - cfg",
+ "description": "Enables GigabitEthernet0/9/0.1 sub interface. Equivalent vppctl command:\n\nvppctl set in state GigabitEthernet0/9/0.1 up\n\nTo enable sub interface, super interface should be enabled first.\n\nTo verify invoke:\n\nvppctl show int",
+ "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7",
+ "responses": [],
+ "folder": "37fd9569-06e3-1f08-fbcc-4b1462107a32",
+ "rawModeData": "{\r\n \"sub-interface\": [\r\n {\r\n \"identifier\": \"1\",\r\n \"vlan-type\": \"802dot1q\",\r\n \"tags\": {\r\n \"tag\": [\r\n {\r\n \"index\": \"0\",\r\n \"dot1q-tag\": {\r\n \"tag-type\": \"dot1q-types:s-vlan\",\r\n \"vlan-id\": \"100\"\r\n }\r\n },\r\n {\r\n \"index\": \"1\",\r\n \"dot1q-tag\": {\r\n \"tag-type\": \"dot1q-types:c-vlan\",\r\n \"vlan-id\": \"any\"\r\n }\r\n }\r\n ]\r\n },\r\n \"match\": {\r\n \"vlan-tagged\": {\r\n \"match-exact-tags\": \"true\"\r\n }\r\n },\r\n \"enabled\": \"true\"\r\n }\r\n ]\r\n}"
+ }
+ ]
+}
diff --git a/infra/translate-api/Readme.adoc b/infra/translate-api/Readme.adoc
new file mode 100644
index 0000000..9e20874
--- /dev/null
+++ b/infra/translate-api/Readme.adoc
@@ -0,0 +1,9 @@
+= Honeycomb translation layer API
+
+Extensible API for translation between Binding Aware data and actual device data.
+Consists of readers and writers responsible for communication with the device.
+
+Provides registry of readers and writers for the data layer.
+For every supported YANG model there should be at least one reader and writer registered.
+Readers and writers form two tree structures matching corresponding YANG models.
+Readers and writers can be attached to any non-leaf YANG node. \ No newline at end of file
diff --git a/infra/translate-api/pom.xml b/infra/translate-api/pom.xml
new file mode 100644
index 0000000..45f00fe
--- /dev/null
+++ b/infra/translate-api/pom.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<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">
+ <parent>
+ <groupId>io.fd.honeycomb.common</groupId>
+ <artifactId>impl-parent</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <relativePath>../../common/impl-parent</relativePath>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>io.fd.honeycomb</groupId>
+ <artifactId>translate-api</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-artifacts</artifactId>
+ <version>2.0.2-Beryllium-SR2</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-binding-api</artifactId>
+ </dependency>
+
+ <!-- Testing Dependencies -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+
+</project>
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/MappingContext.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/MappingContext.java
new file mode 100644
index 0000000..cff766e
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/MappingContext.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.translate;
+
+import com.google.common.base.Optional;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Mapping context is persisted storage where mapping matadata are stored.
+ * A snapshot is created for each transaction to provide consistent view over context data.
+ * After a transaction is successfully finished, objects added to this context are propagated to backing storage.
+ */
+public interface MappingContext extends AutoCloseable {
+
+ /**
+ * Read any mapping context data
+ *
+ * @param currentId Id of an object to read
+ *
+ * @return Relevant mapping context data
+ */
+ <T extends DataObject> Optional<T> read(@Nonnull final InstanceIdentifier<T> currentId);
+
+ /**
+ * Delete the node at specified path.
+ *
+ * @param path Node path
+ */
+ void delete(InstanceIdentifier<?> path);
+
+ /**
+ * Merge the specified data with the currently-present data
+ * at specified path.
+ *
+ * @param path Node path
+ * @param data Data to be merged
+ */
+ <T extends DataObject> void merge(InstanceIdentifier<T> path, T data);
+
+ /**
+ * Replace the data at specified path with supplied data.
+ *
+ * @param path Node path
+ * @param data New node data
+ */
+ <T extends DataObject> void put(InstanceIdentifier<T> path, T data);
+
+ @Override
+ void close();
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModifiableSubtreeManagerRegistryBuilder.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModifiableSubtreeManagerRegistryBuilder.java
new file mode 100644
index 0000000..591a9e9
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModifiableSubtreeManagerRegistryBuilder.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.translate;
+
+import java.util.Collection;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Registry builder where {@link SubtreeManager}s can be added with or without relationships between them.
+ * The relationships express what the order of execution should be.
+ */
+public interface ModifiableSubtreeManagerRegistryBuilder<S extends SubtreeManager<? extends DataObject>> {
+
+ /**
+ * Add a handler responsible for writing only a single complex node.
+ */
+ ModifiableSubtreeManagerRegistryBuilder<S> add(@Nonnull S handler);
+
+ /**
+ * Add a handler responsible for writing multiple complex nodes within a subtree its responsible for. Identifiers for
+ * subtree nodes handled by a single handler have to be relative from {@link DataObject} that represents subtree
+ * root.
+ */
+ ModifiableSubtreeManagerRegistryBuilder<S> subtreeAdd(@Nonnull Set<InstanceIdentifier<?>> handledChildren,
+ @Nonnull S handler);
+
+ /**
+ * Add a handler and make sure it will be executed before handler identifier by relatedType is executed.
+ */
+ ModifiableSubtreeManagerRegistryBuilder<S> addBefore(@Nonnull S handler,
+ @Nonnull InstanceIdentifier<?> relatedType);
+
+ ModifiableSubtreeManagerRegistryBuilder<S> addBefore(@Nonnull S handler,
+ @Nonnull Collection<InstanceIdentifier<?>> relatedTypes);
+
+ ModifiableSubtreeManagerRegistryBuilder<S> subtreeAddBefore(@Nonnull Set<InstanceIdentifier<?>> handledChildren,
+ @Nonnull S handler,
+ @Nonnull InstanceIdentifier<?> relatedType);
+
+ ModifiableSubtreeManagerRegistryBuilder<S> subtreeAddBefore(@Nonnull Set<InstanceIdentifier<?>> handledChildren,
+ @Nonnull S handler,
+ @Nonnull Collection<InstanceIdentifier<?>> relatedTypes);
+
+ /**
+ * Add a handler and make sure it will be executed after handler identifier by relatedType is executed.
+ */
+ ModifiableSubtreeManagerRegistryBuilder<S> addAfter(@Nonnull S handler,
+ @Nonnull InstanceIdentifier<?> relatedType);
+
+ ModifiableSubtreeManagerRegistryBuilder<S> addAfter(@Nonnull S handler,
+ @Nonnull Collection<InstanceIdentifier<?>> relatedTypes);
+
+ ModifiableSubtreeManagerRegistryBuilder<S> subtreeAddAfter(@Nonnull Set<InstanceIdentifier<?>> handledChildren,
+ @Nonnull S handler,
+ @Nonnull InstanceIdentifier<?> relatedType);
+
+ ModifiableSubtreeManagerRegistryBuilder<S> subtreeAddAfter(@Nonnull Set<InstanceIdentifier<?>> handledChildren,
+ @Nonnull S handler,
+ @Nonnull Collection<InstanceIdentifier<?>> relatedTypes);
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationCache.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationCache.java
new file mode 100644
index 0000000..cb2d4fd
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationCache.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.translate;
+
+import com.google.common.collect.Maps;
+import java.util.HashMap;
+
+/**
+ * Simple context class that provides transient storage during one or more read/write operations
+ */
+public class ModificationCache implements AutoCloseable {
+
+ protected final HashMap<Object, Object> map;
+
+ public ModificationCache() {
+ map = Maps.newHashMap();
+ }
+
+ public Object get(final Object o) {
+ return map.get(o);
+ }
+
+ public boolean containsKey(final Object o) {
+ return map.containsKey(o);
+ }
+
+ public Object put(final Object o, final Object o2) {
+ return map.put(o, o2);
+ }
+
+ @Override
+ public void close() {
+ map.clear();
+ }
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationContext.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationContext.java
new file mode 100644
index 0000000..2c039ab
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/ModificationContext.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.translate;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Common context for both writes and reads
+ */
+public interface ModificationContext extends AutoCloseable {
+
+ /**
+ * Get key value transient storage for customizers. Is cleared for each new transaction.
+ *
+ * @return Context for customizers
+ */
+ @Nonnull
+ ModificationCache getModificationCache();
+
+ /**
+ * Get persistent storage for mapping context. This context survives a modification.
+ *
+ * @return Mapping context accessor
+ */
+ @Nonnull
+ MappingContext getMappingContext();
+
+ @Override
+ void close();
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/SubtreeManager.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/SubtreeManager.java
new file mode 100644
index 0000000..4084276
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/SubtreeManager.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.translate;
+
+import com.google.common.annotations.Beta;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Base identifiable subtree manager(reader, writer etc.)
+ *
+ * @param <D> Specific DataObject derived type, that is managed by this manager
+ */
+@Beta
+public interface SubtreeManager<D extends DataObject> {
+
+ /**
+ * Gets the type of node managed by this reader.
+ *
+ * @return Absolute instance identifier for managed type
+ */
+ @Nonnull
+ InstanceIdentifier<D> getManagedDataObjectType();
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/SubtreeManagerRegistryBuilder.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/SubtreeManagerRegistryBuilder.java
new file mode 100644
index 0000000..2434ded
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/SubtreeManagerRegistryBuilder.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.translate;
+
+public interface SubtreeManagerRegistryBuilder<R> {
+
+ R build();
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/TranslationException.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/TranslationException.java
new file mode 100644
index 0000000..ee00499
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/TranslationException.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.translate;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * Base exception for the translation layer
+ */
+@Beta
+public class TranslationException extends Exception {
+
+ public TranslationException(final String s) {
+ super(s);
+ }
+
+ public TranslationException(final String s, final Throwable cause) {
+ super(s, cause);
+ }
+
+ public TranslationException(final Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ListReader.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ListReader.java
new file mode 100644
index 0000000..13a7a55
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ListReader.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.translate.read;
+
+import com.google.common.annotations.Beta;
+import java.util.Collections;
+import java.util.List;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * List reader, allowing read of all the elements.
+ *
+ * @param <D> Specific DataObject derived type, that is handled by this reader
+ */
+@Beta
+public interface ListReader
+ <D extends DataObject & Identifiable<K>, K extends Identifier<D>, B extends Builder<D>> extends Reader<D, B> {
+
+ /**
+ * Read all elements in this list.
+ *
+ * @param id Wildcarded identifier of list managed by this reader
+ * @param ctx Read context
+ *
+ * @return List of all entries in this list
+ * @throws ReadFailedException if read was unsuccessful
+ */
+ @Nonnull
+ List<D> readList(@Nonnull final InstanceIdentifier<D> id, @Nonnull final ReadContext ctx)
+ throws ReadFailedException;
+
+ /**
+ * Get IDs for all entries in the list.
+ */
+ List<K> getAllIds(@Nonnull InstanceIdentifier<D> id, @Nonnull ReadContext ctx)
+ throws ReadFailedException;
+
+ /**
+ * Merge read data into provided parent builder.
+ */
+ void merge(@Nonnull final Builder<? extends DataObject> builder, @Nonnull final List<D> readData);
+
+ @Override
+ default void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final D readValue) {
+ merge(parentBuilder, Collections.singletonList(readValue));
+ }
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadContext.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadContext.java
new file mode 100644
index 0000000..e3ddd42
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadContext.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.translate.read;
+
+import io.fd.honeycomb.v3po.translate.ModificationContext;
+
+/**
+ * Context providing information about current state of DataTree to readers
+ */
+public interface ReadContext extends ModificationContext {
+
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadFailedException.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadFailedException.java
new file mode 100644
index 0000000..51d4fcb
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReadFailedException.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.translate.read;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.honeycomb.v3po.translate.TranslationException;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Thrown when a reader or customizer is not able to read data for the given id.
+ */
+public class ReadFailedException extends TranslationException {
+
+ private final InstanceIdentifier<?> failedId;
+
+ /**
+ * Constructs an ReadFailedException given data id and exception cause.
+ *
+ * @param failedId instance identifier of the data object that could not be read
+ * @param cause the cause of read failure
+ */
+ public ReadFailedException(@Nonnull final InstanceIdentifier<?> failedId, final Throwable cause) {
+ super("Failed to read " + failedId, cause);
+ this.failedId = checkNotNull(failedId, "failedId should not be null");
+ }
+
+ /**
+ * Constructs an ReadFailedException given data id.
+ *
+ * @param failedId instance identifier of the data object that could not be read
+ */
+ public ReadFailedException(@Nonnull final InstanceIdentifier<?> failedId) {
+ this(failedId, null);
+ }
+
+ /**
+ * Returns id of the data object that could not be read.
+ *
+ * @return data object instance identifier
+ */
+ @Nonnull
+ public InstanceIdentifier<?> getFailedId() {
+ return failedId;
+ }
+}
diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/Reader.java b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/Reader.java
new file mode 100644
index 0000000..d0bf0de
--- /dev/null
+++ b/infra/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/Reader.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.translate.read;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Optional;
+import io.fd.honeycomb.v3po.translate.SubtreeManager;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Base reader, responsible for translation between DataObjects and any other side.
+ *
+ * @param <D> Specific DataObject derived type, that is handled by this reader
+ */
+@Beta
+public interface Reader<D extends DataObject, B extends Builder<D>> extends SubtreeManager<D> {
+
+ // TODO make async
+
+ /**
+ * Reads data identified by id
+ *
+ * @pa