From c7ca517b00f2682987aef3ac390dfc04155a8aee Mon Sep 17 00:00:00 2001 From: Maros Marsalek Date: Tue, 12 Apr 2016 10:13:14 +0200 Subject: HONEYCOMB-9: Split impl module into smaller parts Change-Id: I9232e0adfe611cb97951080839b28a7b62ba5484 Signed-off-by: Maros Marsalek --- v3po/artifacts/pom.xml | 25 ++ v3po/features/pom.xml | 25 ++ v3po/features/src/main/features/features.xml | 5 + v3po/impl/pom.xml | 10 + .../v3po/impl/data/VppConfigDataTree.java | 8 +- .../data/VppDataBrokerInitializationProvider.java | 2 +- .../fd/honeycomb/v3po/impl/data/VppDataTree.java | 5 +- .../v3po/impl/data/VppOperationalDataTree.java | 8 +- .../v3po/impl/data/VppReaderRegistry.java | 30 +-- .../v3po/impl/data/VppWriteTransaction.java | 2 +- .../v3po/impl/data/VppWriterRegistry.java | 27 ++- .../v3po/impl/trans/ReadFailedException.java | 60 ----- .../honeycomb/v3po/impl/trans/SubtreeManager.java | 39 --- .../v3po/impl/trans/VppApiInvocationException.java | 76 ------ .../fd/honeycomb/v3po/impl/trans/VppException.java | 38 --- .../v3po/impl/trans/r/ChildVppReader.java | 51 ---- .../honeycomb/v3po/impl/trans/r/ListVppReader.java | 48 ---- .../honeycomb/v3po/impl/trans/r/ReadContext.java | 37 --- .../v3po/impl/trans/r/ReaderRegistry.java | 44 ---- .../fd/honeycomb/v3po/impl/trans/r/VppReader.java | 52 ---- .../trans/r/impl/AbstractCompositeVppReader.java | 233 ------------------ .../impl/trans/r/impl/CompositeChildVppReader.java | 104 -------- .../impl/trans/r/impl/CompositeListVppReader.java | 137 ----------- .../impl/trans/r/impl/CompositeRootVppReader.java | 92 ------- .../trans/r/impl/spi/ChildVppReaderCustomizer.java | 41 ---- .../trans/r/impl/spi/ListVppReaderCustomizer.java | 54 ----- .../trans/r/impl/spi/RootVppReaderCustomizer.java | 52 ---- .../trans/r/util/DelegatingReaderRegistry.java | 113 --------- .../impl/trans/r/util/NoopReaderCustomizer.java | 31 --- .../r/util/ReflexiveChildReaderCustomizer.java | 57 ----- .../r/util/ReflexiveRootReaderCustomizer.java | 42 ---- .../fd/honeycomb/v3po/impl/trans/util/Context.java | 49 ---- .../v3po/impl/trans/util/ReflectionUtils.java | 79 ------ .../v3po/impl/trans/util/VppApiCustomizer.java | 41 ---- .../honeycomb/v3po/impl/trans/util/VppRWUtils.java | 178 -------------- .../v3po/impl/trans/w/ChildVppWriter.java | 66 ----- .../fd/honeycomb/v3po/impl/trans/w/VppWriter.java | 49 ---- .../honeycomb/v3po/impl/trans/w/WriteContext.java | 60 ----- .../v3po/impl/trans/w/WriterRegistry.java | 135 ----------- .../trans/w/impl/AbstractCompositeVppWriter.java | 270 --------------------- .../impl/trans/w/impl/CompositeChildVppWriter.java | 105 -------- .../impl/trans/w/impl/CompositeListVppWriter.java | 178 -------------- .../impl/trans/w/impl/CompositeRootVppWriter.java | 72 ------ .../trans/w/impl/spi/ChildVppWriterCustomizer.java | 42 ---- .../trans/w/impl/spi/ListVppWriterCustomizer.java | 45 ---- .../trans/w/impl/spi/RootVppWriterCustomizer.java | 67 ----- .../trans/w/util/DelegatingWriterRegistry.java | 176 -------------- .../impl/trans/w/util/NoopWriterCustomizer.java | 49 ---- .../w/util/ReflexiveChildWriterCustomizer.java | 59 ----- .../impl/trans/w/util/TransactionWriteContext.java | 101 -------- .../v3po/impl/vpp/BridgeDomainCustomizer.java | 138 ----------- .../v3po/impl/vppstate/BridgeDomainCustomizer.java | 136 ----------- .../v3po/impl/vppstate/VersionCustomizer.java | 59 ----- .../v3po/impl/data/VPPConfigDataTreeTest.java | 6 +- .../VppDataBrokerInitializationProviderTest.java | 2 +- .../v3po/impl/data/VppOperationalDataTreeTest.java | 8 +- .../v3po/impl/trans/ReadFailedExceptionTest.java | 53 ---- .../impl/trans/VppApiInvocationExceptionTest.java | 46 ---- .../trans/w/util/DelegatingWriterRegistryTest.java | 189 --------------- .../trans/w/util/TransactionWriteContextTest.java | 122 ---------- .../v3po/impl/vpp/BridgeDomainCustomizerTest.java | 269 -------------------- .../v3po/impl/vpp/BridgeDomainTestUtils.java | 64 ----- .../io/fd/honeycomb/v3po/impl/vpp/VppTest.java | 174 ------------- .../io/fd/honeycomb/v3po/impl/vpp/VppUtils.java | 62 ----- .../honeycomb/v3po/impl/vppstate/VppStateTest.java | 259 -------------------- .../v3po/impl/vppstate/VppStateUtils.java | 77 ------ v3po/pom.xml | 5 + v3po/v3po2vpp/pom.xml | 92 +++++++ .../facade/v3po/vpp/BridgeDomainCustomizer.java | 138 +++++++++++ .../v3po/vppstate/BridgeDomainCustomizer.java | 136 +++++++++++ .../facade/v3po/vppstate/VersionCustomizer.java | 59 +++++ .../v3po/vpp/BridgeDomainCustomizerTest.java | 269 ++++++++++++++++++++ .../vpp/facade/v3po/vpp/BridgeDomainTestUtils.java | 64 +++++ .../v3po/vpp/facade/v3po/vpp/VppTest.java | 174 +++++++++++++ .../v3po/vpp/facade/v3po/vpp/VppUtils.java | 62 +++++ .../vpp/facade/v3po/vppstate/VppStateTest.java | 259 ++++++++++++++++++++ .../vpp/facade/v3po/vppstate/VppStateUtils.java | 77 ++++++ v3po/vpp-facade-api/pom.xml | 73 ++++++ .../io/fd/honeycomb/v3po/vpp/facade/Context.java | 49 ++++ .../honeycomb/v3po/vpp/facade/SubtreeManager.java | 39 +++ .../v3po/vpp/facade/VppApiInvocationException.java | 76 ++++++ .../fd/honeycomb/v3po/vpp/facade/VppException.java | 38 +++ .../v3po/vpp/facade/read/ChildVppReader.java | 50 ++++ .../v3po/vpp/facade/read/ListVppReader.java | 47 ++++ .../v3po/vpp/facade/read/ReadContext.java | 37 +++ .../v3po/vpp/facade/read/ReadFailedException.java | 61 +++++ .../v3po/vpp/facade/read/ReaderRegistry.java | 43 ++++ .../honeycomb/v3po/vpp/facade/read/VppReader.java | 51 ++++ .../v3po/vpp/facade/write/ChildVppWriter.java | 66 +++++ .../honeycomb/v3po/vpp/facade/write/VppWriter.java | 49 ++++ .../v3po/vpp/facade/write/WriteContext.java | 60 +++++ .../v3po/vpp/facade/write/WriterRegistry.java | 135 +++++++++++ .../v3po/vpp/facade/ReadFailedExceptionTest.java | 51 ++++ .../vpp/facade/VppApiInvocationExceptionTest.java | 44 ++++ v3po/vpp-facade-impl/pom.xml | 88 +++++++ .../impl/read/AbstractCompositeVppReader.java | 232 ++++++++++++++++++ .../facade/impl/read/CompositeChildVppReader.java | 104 ++++++++ .../facade/impl/read/CompositeListVppReader.java | 137 +++++++++++ .../facade/impl/read/CompositeRootVppReader.java | 91 +++++++ .../impl/write/AbstractCompositeVppWriter.java | 270 +++++++++++++++++++++ .../facade/impl/write/CompositeChildVppWriter.java | 105 ++++++++ .../facade/impl/write/CompositeListVppWriter.java | 178 ++++++++++++++ .../facade/impl/write/CompositeRootVppWriter.java | 72 ++++++ .../write/util/DelegatingWriterRegistryTest.java | 189 +++++++++++++++ .../write/util/TransactionWriteContextTest.java | 138 +++++++++++ v3po/vpp-facade-spi/pom.xml | 72 ++++++ .../facade/spi/read/ChildVppReaderCustomizer.java | 41 ++++ .../facade/spi/read/ListVppReaderCustomizer.java | 54 +++++ .../facade/spi/read/RootVppReaderCustomizer.java | 52 ++++ .../facade/spi/write/ChildVppWriterCustomizer.java | 42 ++++ .../facade/spi/write/ListVppWriterCustomizer.java | 45 ++++ .../facade/spi/write/RootVppWriterCustomizer.java | 67 +++++ v3po/vpp-facade-utils/pom.xml | 95 ++++++++ .../impl/read/util/DelegatingReaderRegistry.java | 113 +++++++++ .../impl/read/util/NoopReaderCustomizer.java | 32 +++ .../read/util/ReflexiveChildReaderCustomizer.java | 57 +++++ .../read/util/ReflexiveRootReaderCustomizer.java | 42 ++++ .../v3po/vpp/facade/impl/util/ReflectionUtils.java | 79 ++++++ .../vpp/facade/impl/util/VppApiCustomizer.java | 41 ++++ .../v3po/vpp/facade/impl/util/VppRWUtils.java | 178 ++++++++++++++ .../impl/write/util/DelegatingWriterRegistry.java | 176 ++++++++++++++ .../impl/write/util/NoopWriterCustomizer.java | 49 ++++ .../write/util/ReflexiveChildWriterCustomizer.java | 59 +++++ .../impl/write/util/TransactionWriteContext.java | 101 ++++++++ .../write/util/DelegatingWriterRegistryTest.java | 188 ++++++++++++++ .../write/util/TransactionWriteContextTest.java | 138 +++++++++++ 126 files changed, 5743 insertions(+), 4919 deletions(-) delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/ReadFailedException.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/SubtreeManager.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/VppApiInvocationException.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/VppException.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/ChildVppReader.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/ListVppReader.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/ReadContext.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/ReaderRegistry.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/VppReader.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/AbstractCompositeVppReader.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/CompositeChildVppReader.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/CompositeListVppReader.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/CompositeRootVppReader.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/spi/ChildVppReaderCustomizer.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/spi/ListVppReaderCustomizer.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/spi/RootVppReaderCustomizer.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/util/DelegatingReaderRegistry.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/util/NoopReaderCustomizer.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/util/ReflexiveChildReaderCustomizer.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/util/ReflexiveRootReaderCustomizer.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/Context.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/ReflectionUtils.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/VppApiCustomizer.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/VppRWUtils.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/ChildVppWriter.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/VppWriter.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/WriteContext.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/WriterRegistry.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/impl/AbstractCompositeVppWriter.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/impl/CompositeChildVppWriter.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/impl/CompositeListVppWriter.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/impl/CompositeRootVppWriter.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/impl/spi/ChildVppWriterCustomizer.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/impl/spi/ListVppWriterCustomizer.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/impl/spi/RootVppWriterCustomizer.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/util/DelegatingWriterRegistry.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/util/NoopWriterCustomizer.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/util/ReflexiveChildWriterCustomizer.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/util/TransactionWriteContext.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainCustomizer.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vppstate/BridgeDomainCustomizer.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vppstate/VersionCustomizer.java delete mode 100644 v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/ReadFailedExceptionTest.java delete mode 100644 v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/VppApiInvocationExceptionTest.java delete mode 100644 v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/w/util/DelegatingWriterRegistryTest.java delete mode 100644 v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/w/util/TransactionWriteContextTest.java delete mode 100644 v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainCustomizerTest.java delete mode 100644 v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainTestUtils.java delete mode 100644 v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/VppTest.java delete mode 100644 v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/VppUtils.java delete mode 100644 v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vppstate/VppStateTest.java delete mode 100644 v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vppstate/VppStateUtils.java create mode 100644 v3po/v3po2vpp/pom.xml create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vpp/BridgeDomainCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vppstate/BridgeDomainCustomizer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vppstate/VersionCustomizer.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vpp/BridgeDomainCustomizerTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vpp/BridgeDomainTestUtils.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vpp/VppTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vpp/VppUtils.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vppstate/VppStateTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vppstate/VppStateUtils.java create mode 100644 v3po/vpp-facade-api/pom.xml create mode 100644 v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/Context.java create mode 100644 v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/SubtreeManager.java create mode 100644 v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/VppApiInvocationException.java create mode 100644 v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/VppException.java create mode 100644 v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/read/ChildVppReader.java create mode 100644 v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/read/ListVppReader.java create mode 100644 v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/read/ReadContext.java create mode 100644 v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/read/ReadFailedException.java create mode 100644 v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/read/ReaderRegistry.java create mode 100644 v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/read/VppReader.java create mode 100644 v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/write/ChildVppWriter.java create mode 100644 v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/write/VppWriter.java create mode 100644 v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/write/WriteContext.java create mode 100644 v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/write/WriterRegistry.java create mode 100644 v3po/vpp-facade-api/src/test/java/io/fd/honeycomb/v3po/vpp/facade/ReadFailedExceptionTest.java create mode 100644 v3po/vpp-facade-api/src/test/java/io/fd/honeycomb/v3po/vpp/facade/VppApiInvocationExceptionTest.java create mode 100644 v3po/vpp-facade-impl/pom.xml create mode 100644 v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/AbstractCompositeVppReader.java create mode 100644 v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/CompositeChildVppReader.java create mode 100644 v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/CompositeListVppReader.java create mode 100644 v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/CompositeRootVppReader.java create mode 100644 v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/AbstractCompositeVppWriter.java create mode 100644 v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/CompositeChildVppWriter.java create mode 100644 v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/CompositeListVppWriter.java create mode 100644 v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/CompositeRootVppWriter.java create mode 100644 v3po/vpp-facade-impl/src/test/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/DelegatingWriterRegistryTest.java create mode 100644 v3po/vpp-facade-impl/src/test/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/TransactionWriteContextTest.java create mode 100644 v3po/vpp-facade-spi/pom.xml create mode 100644 v3po/vpp-facade-spi/src/main/java/io/fd/honeycomb/v3po/vpp/facade/spi/read/ChildVppReaderCustomizer.java create mode 100644 v3po/vpp-facade-spi/src/main/java/io/fd/honeycomb/v3po/vpp/facade/spi/read/ListVppReaderCustomizer.java create mode 100644 v3po/vpp-facade-spi/src/main/java/io/fd/honeycomb/v3po/vpp/facade/spi/read/RootVppReaderCustomizer.java create mode 100644 v3po/vpp-facade-spi/src/main/java/io/fd/honeycomb/v3po/vpp/facade/spi/write/ChildVppWriterCustomizer.java create mode 100644 v3po/vpp-facade-spi/src/main/java/io/fd/honeycomb/v3po/vpp/facade/spi/write/ListVppWriterCustomizer.java create mode 100644 v3po/vpp-facade-spi/src/main/java/io/fd/honeycomb/v3po/vpp/facade/spi/write/RootVppWriterCustomizer.java create mode 100644 v3po/vpp-facade-utils/pom.xml create mode 100644 v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/util/DelegatingReaderRegistry.java create mode 100644 v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/util/NoopReaderCustomizer.java create mode 100644 v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/util/ReflexiveChildReaderCustomizer.java create mode 100644 v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/util/ReflexiveRootReaderCustomizer.java create mode 100644 v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/util/ReflectionUtils.java create mode 100644 v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/util/VppApiCustomizer.java create mode 100644 v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/util/VppRWUtils.java create mode 100644 v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/DelegatingWriterRegistry.java create mode 100644 v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/NoopWriterCustomizer.java create mode 100644 v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/ReflexiveChildWriterCustomizer.java create mode 100644 v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/TransactionWriteContext.java create mode 100644 v3po/vpp-facade-utils/src/test/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/DelegatingWriterRegistryTest.java create mode 100644 v3po/vpp-facade-utils/src/test/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/TransactionWriteContextTest.java (limited to 'v3po') diff --git a/v3po/artifacts/pom.xml b/v3po/artifacts/pom.xml index b4c283973..cdfb7c27f 100644 --- a/v3po/artifacts/pom.xml +++ b/v3po/artifacts/pom.xml @@ -29,6 +29,31 @@ v3po-api ${project.version} + + ${project.groupId} + vpp-facade-api + ${project.version} + + + ${project.groupId} + vpp-facade-spi + ${project.version} + + + ${project.groupId} + vpp-facade-impl + ${project.version} + + + ${project.groupId} + vpp-facade-utils + ${project.version} + + + ${project.groupId} + v3po2vpp + ${project.version} + ${project.groupId} v3po-impl diff --git a/v3po/features/pom.xml b/v3po/features/pom.xml index 77473cade..142d803c1 100644 --- a/v3po/features/pom.xml +++ b/v3po/features/pom.xml @@ -133,6 +133,31 @@ v3po-api ${project.version} + + ${project.groupId} + vpp-facade-api + ${project.version} + + + ${project.groupId} + vpp-facade-spi + ${project.version} + + + ${project.groupId} + vpp-facade-impl + ${project.version} + + + ${project.groupId} + vpp-facade-utils + ${project.version} + + + ${project.groupId} + v3po2vpp + ${project.version} + io.fd.vpp vppjapi diff --git a/v3po/features/src/main/features/features.xml b/v3po/features/src/main/features/features.xml index 3d3ffdb3e..cea5999ae 100644 --- a/v3po/features/src/main/features/features.xml +++ b/v3po/features/src/main/features/features.xml @@ -35,6 +35,11 @@ odl-netconf-connector-ssh odl-netconf-mdsal mvn:io.fd.honeycomb.v3po/v3po-impl/${project.version} + mvn:io.fd.honeycomb.v3po/vpp-facade-api/${project.version} + mvn:io.fd.honeycomb.v3po/vpp-facade-spi/${project.version} + mvn:io.fd.honeycomb.v3po/vpp-facade-utils/${project.version} + mvn:io.fd.honeycomb.v3po/vpp-facade-impl/${project.version} + mvn:io.fd.honeycomb.v3po/v3po2vpp/${project.version} wrap:mvn:io.fd.vpp/vppjapi/1.0.0-SNAPSHOT mvn:io.fd.honeycomb.v3po/v3po-impl/${project.version}/xml/config mvn:io.fd.honeycomb.v3po/v3po-impl/${project.version}/xml/netconf diff --git a/v3po/impl/pom.xml b/v3po/impl/pom.xml index a47b6a133..a8109a888 100644 --- a/v3po/impl/pom.xml +++ b/v3po/impl/pom.xml @@ -34,6 +34,16 @@ v3po-api ${project.version} + + ${project.groupId} + vpp-facade-impl + ${project.version} + + + ${project.groupId} + v3po2vpp + ${project.version} + io.fd.vpp diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppConfigDataTree.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppConfigDataTree.java index 1982bc707..72848ad0f 100644 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppConfigDataTree.java +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppConfigDataTree.java @@ -21,10 +21,10 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.base.Optional; import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.Futures; -import io.fd.honeycomb.v3po.impl.trans.VppException; -import io.fd.honeycomb.v3po.impl.trans.w.WriteContext; -import io.fd.honeycomb.v3po.impl.trans.w.WriterRegistry; -import io.fd.honeycomb.v3po.impl.trans.w.util.TransactionWriteContext; +import io.fd.honeycomb.v3po.vpp.facade.VppException; +import io.fd.honeycomb.v3po.vpp.facade.impl.write.util.TransactionWriteContext; +import io.fd.honeycomb.v3po.vpp.facade.write.WriteContext; +import io.fd.honeycomb.v3po.vpp.facade.write.WriterRegistry; import java.util.Collections; import java.util.Map; import javax.annotation.Nonnull; diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerInitializationProvider.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerInitializationProvider.java index 2a14f48b1..d84f0b7b7 100644 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerInitializationProvider.java +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerInitializationProvider.java @@ -24,7 +24,7 @@ import com.google.common.util.concurrent.AsyncFunction; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import io.fd.honeycomb.v3po.impl.LoggingFuturesCallBack; -import io.fd.honeycomb.v3po.impl.trans.r.ReaderRegistry; +import io.fd.honeycomb.v3po.vpp.facade.read.ReaderRegistry; import java.util.Collection; import java.util.Collections; import javassist.ClassPool; diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataTree.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataTree.java index 7fd9b2e3a..7e62b57b0 100644 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataTree.java +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataTree.java @@ -17,7 +17,7 @@ package io.fd.honeycomb.v3po.impl.data; import com.google.common.annotations.Beta; -import io.fd.honeycomb.v3po.impl.trans.VppException; +import io.fd.honeycomb.v3po.vpp.facade.VppException; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException; @@ -33,8 +33,7 @@ public interface VppDataTree { * @throws DataValidationFailedException if modification data is not valid * @throws VppException if commit failed while updating VPP state */ - void commit(final DataTreeModification modification) throws DataValidationFailedException, - VppException; + void commit(final DataTreeModification modification) throws DataValidationFailedException, VppException; /** * Creates read-only snapshot of a VppDataTree. diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppOperationalDataTree.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppOperationalDataTree.java index d73c22a6d..12d281611 100644 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppOperationalDataTree.java +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppOperationalDataTree.java @@ -26,10 +26,10 @@ 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.impl.trans.ReadFailedException; -import io.fd.honeycomb.v3po.impl.trans.r.ReadContext; -import io.fd.honeycomb.v3po.impl.trans.r.ReaderRegistry; -import io.fd.honeycomb.v3po.impl.trans.util.Context; +import io.fd.honeycomb.v3po.vpp.facade.Context; +import io.fd.honeycomb.v3po.vpp.facade.read.ReadContext; +import io.fd.honeycomb.v3po.vpp.facade.read.ReadFailedException; +import io.fd.honeycomb.v3po.vpp.facade.read.ReaderRegistry; import java.util.Collection; import java.util.Map; import javax.annotation.Nonnull; diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppReaderRegistry.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppReaderRegistry.java index fc6a51add..ba1865494 100644 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppReaderRegistry.java +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppReaderRegistry.java @@ -18,20 +18,20 @@ package io.fd.honeycomb.v3po.impl.data; import com.google.common.base.Optional; import com.google.common.collect.Multimap; -import io.fd.honeycomb.v3po.impl.trans.ReadFailedException; -import io.fd.honeycomb.v3po.impl.trans.r.ChildVppReader; -import io.fd.honeycomb.v3po.impl.trans.r.ReadContext; -import io.fd.honeycomb.v3po.impl.trans.r.ReaderRegistry; -import io.fd.honeycomb.v3po.impl.trans.r.VppReader; -import io.fd.honeycomb.v3po.impl.trans.r.impl.CompositeChildVppReader; -import io.fd.honeycomb.v3po.impl.trans.r.impl.CompositeListVppReader; -import io.fd.honeycomb.v3po.impl.trans.r.impl.CompositeRootVppReader; -import io.fd.honeycomb.v3po.impl.trans.r.util.DelegatingReaderRegistry; -import io.fd.honeycomb.v3po.impl.trans.r.util.ReflexiveChildReaderCustomizer; -import io.fd.honeycomb.v3po.impl.trans.r.util.ReflexiveRootReaderCustomizer; -import io.fd.honeycomb.v3po.impl.trans.util.VppRWUtils; -import io.fd.honeycomb.v3po.impl.vppstate.BridgeDomainCustomizer; -import io.fd.honeycomb.v3po.impl.vppstate.VersionCustomizer; +import io.fd.honeycomb.v3po.vpp.facade.impl.read.CompositeChildVppReader; +import io.fd.honeycomb.v3po.vpp.facade.impl.read.CompositeListVppReader; +import io.fd.honeycomb.v3po.vpp.facade.impl.read.CompositeRootVppReader; +import io.fd.honeycomb.v3po.vpp.facade.impl.read.util.DelegatingReaderRegistry; +import io.fd.honeycomb.v3po.vpp.facade.impl.read.util.ReflexiveChildReaderCustomizer; +import io.fd.honeycomb.v3po.vpp.facade.impl.read.util.ReflexiveRootReaderCustomizer; +import io.fd.honeycomb.v3po.vpp.facade.impl.util.VppRWUtils; +import io.fd.honeycomb.v3po.vpp.facade.read.ChildVppReader; +import io.fd.honeycomb.v3po.vpp.facade.read.ReadContext; +import io.fd.honeycomb.v3po.vpp.facade.read.ReadFailedException; +import io.fd.honeycomb.v3po.vpp.facade.read.ReaderRegistry; +import io.fd.honeycomb.v3po.vpp.facade.read.VppReader; +import io.fd.honeycomb.v3po.vpp.facade.v3po.vppstate.BridgeDomainCustomizer; +import io.fd.honeycomb.v3po.vpp.facade.v3po.vppstate.VersionCustomizer; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -98,7 +98,7 @@ public class VppReaderRegistry implements ReaderRegistry { @Nonnull @Override public Multimap, ? extends DataObject> readAll( - @Nonnull final ReadContext ctx) throws io.fd.honeycomb.v3po.impl.trans.ReadFailedException { + @Nonnull final ReadContext ctx) throws ReadFailedException { return reader.readAll(ctx); } diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppWriteTransaction.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppWriteTransaction.java index 299898bd3..1baa586b1 100644 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppWriteTransaction.java +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppWriteTransaction.java @@ -26,7 +26,7 @@ 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.impl.trans.VppException; +import io.fd.honeycomb.v3po.vpp.facade.VppException; import javax.annotation.Nonnull; import javax.annotation.concurrent.NotThreadSafe; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppWriterRegistry.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppWriterRegistry.java index defcca47e..04b4bd631 100644 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppWriterRegistry.java +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppWriterRegistry.java @@ -16,18 +16,19 @@ package io.fd.honeycomb.v3po.impl.data; -import io.fd.honeycomb.v3po.impl.trans.VppException; -import io.fd.honeycomb.v3po.impl.trans.util.VppRWUtils; -import io.fd.honeycomb.v3po.impl.trans.w.ChildVppWriter; -import io.fd.honeycomb.v3po.impl.trans.w.VppWriter; -import io.fd.honeycomb.v3po.impl.trans.w.WriteContext; -import io.fd.honeycomb.v3po.impl.trans.w.WriterRegistry; -import io.fd.honeycomb.v3po.impl.trans.w.impl.CompositeChildVppWriter; -import io.fd.honeycomb.v3po.impl.trans.w.impl.CompositeListVppWriter; -import io.fd.honeycomb.v3po.impl.trans.w.impl.CompositeRootVppWriter; -import io.fd.honeycomb.v3po.impl.trans.w.util.DelegatingWriterRegistry; -import io.fd.honeycomb.v3po.impl.trans.w.util.NoopWriterCustomizer; -import io.fd.honeycomb.v3po.impl.trans.w.util.ReflexiveChildWriterCustomizer; +import io.fd.honeycomb.v3po.vpp.facade.VppException; +import io.fd.honeycomb.v3po.vpp.facade.impl.util.VppRWUtils; +import io.fd.honeycomb.v3po.vpp.facade.impl.write.CompositeChildVppWriter; +import io.fd.honeycomb.v3po.vpp.facade.impl.write.CompositeListVppWriter; +import io.fd.honeycomb.v3po.vpp.facade.impl.write.CompositeRootVppWriter; +import io.fd.honeycomb.v3po.vpp.facade.impl.write.util.DelegatingWriterRegistry; +import io.fd.honeycomb.v3po.vpp.facade.impl.write.util.NoopWriterCustomizer; +import io.fd.honeycomb.v3po.vpp.facade.impl.write.util.ReflexiveChildWriterCustomizer; +import io.fd.honeycomb.v3po.vpp.facade.v3po.vpp.BridgeDomainCustomizer; +import io.fd.honeycomb.v3po.vpp.facade.write.ChildVppWriter; +import io.fd.honeycomb.v3po.vpp.facade.write.VppWriter; +import io.fd.honeycomb.v3po.vpp.facade.write.WriteContext; +import io.fd.honeycomb.v3po.vpp.facade.write.WriterRegistry; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -58,7 +59,7 @@ public class VppWriterRegistry implements WriterRegistry { private static CompositeRootVppWriter initVppStateWriter(@Nonnull final vppApi vppApi) { final CompositeListVppWriter bridgeDomainWriter = new CompositeListVppWriter<>( BridgeDomain.class, - new io.fd.honeycomb.v3po.impl.vpp.BridgeDomainCustomizer(vppApi)); + new BridgeDomainCustomizer(vppApi)); final ChildVppWriter bridgeDomainsWriter = new CompositeChildVppWriter<>( BridgeDomains.class, diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/ReadFailedException.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/ReadFailedException.java deleted file mode 100644 index 4da8b0e73..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/ReadFailedException.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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.impl.trans; - -import static com.google.common.base.Preconditions.checkNotNull; - -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Thrown when Vpp reader or customizer is not able to read data for the given id. - */ -public class ReadFailedException extends VppException { - - 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/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/SubtreeManager.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/SubtreeManager.java deleted file mode 100644 index 0aa927cd0..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/SubtreeManager.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.impl.trans; - -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 Specific DataObject derived type, that is managed by this manager - */ -@Beta -public interface SubtreeManager { - - /** - * Gets the type of node managed by this reader - * - * @return Class object for node managed by this reader - */ - @Nonnull - InstanceIdentifier getManagedDataObjectType(); -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/VppApiInvocationException.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/VppApiInvocationException.java deleted file mode 100644 index 042c627ef..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/VppApiInvocationException.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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.impl.trans; - -import com.google.common.annotations.Beta; -import com.google.common.base.Preconditions; -import javax.annotation.Nonnull; - -/** - * Thrown when Vpp jAPI method invocation failed. - */ -@Beta -public class VppApiInvocationException extends VppException { - private final String methodName; - private final int ctxId; - private final int errorCode; - - /** - * Constructs an VppApiInvocationFailedException with the specified api method name and error code. - * - * @param methodName method name that failed to invoke - * @param ctxId api request context identifier - * @param errorCode negative error code value associated with this failure - * @throws NullPointerException if apiMethodName is null - * @throws IllegalArgumentException if errorCode is nonnegative - */ - public VppApiInvocationException(@Nonnull final String methodName, final int ctxId, final int errorCode) { - super(String.format("vppApi.%s failed with error code: %d (ctxId=%d) ", methodName, errorCode, ctxId)); - this.methodName = Preconditions.checkNotNull(methodName, "apiMethodName is null!"); - this.ctxId = ctxId; - Preconditions.checkArgument(errorCode < 0); - this.errorCode = errorCode; - } - - /** - * Returns method name that failed to invoke. - * - * @return method name - */ - public String getMethodName() { - return methodName; - } - - /** - * Returns api request context identifier. - * - * @return value of context identifier - */ - public int getCtxId() { - return ctxId; - } - - /** - * Returns the error code associated with this failure. - * - * @return a negative integer error code - */ - public int getErrorCode() { - return errorCode; - } -} - diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/VppException.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/VppException.java deleted file mode 100644 index aadeaa996..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/VppException.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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.impl.trans; - -import com.google.common.annotations.Beta; - -/** - * Base exception for Vpp translation layer - */ -@Beta -public class VppException extends Exception { - - public VppException(final String s) { - super(s); - } - - public VppException(final String s, final Throwable cause) { - super(s, cause); - } - - public VppException(final Throwable cause) { - super(cause); - } -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/ChildVppReader.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/ChildVppReader.java deleted file mode 100644 index 8135e8cd2..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/ChildVppReader.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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.impl.trans.r; - -import com.google.common.annotations.Beta; -import io.fd.honeycomb.v3po.impl.trans.ReadFailedException; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Child VPP reader allowing its parent to pass the builder object - * - * @param Specific DataObject derived type, that is handled by this reader - */ -@Beta -public interface ChildVppReader extends VppReader { - - /** - * Reads subtree starting from node managed by this reader and place the subtree within parent builder object if the - * data exists. - * - * @param id Unique identifier pointing to the node managed by this reader. Useful when necessary to - * determine the exact position within more complex subtrees. - * @param parentBuilder Builder of parent DataObject. Objects read on this level (if any) must be placed into the - * parent builder. - * @param ctx Read context - * - * @throws ReadFailedException if read was unsuccessful - */ - void read(@Nonnull final InstanceIdentifier id, - @Nonnull final Builder parentBuilder, - @Nonnull final ReadContext ctx) throws ReadFailedException; - -} - diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/ListVppReader.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/ListVppReader.java deleted file mode 100644 index e37c76634..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/ListVppReader.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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.impl.trans.r; - -import com.google.common.annotations.Beta; -import io.fd.honeycomb.v3po.impl.trans.ReadFailedException; -import java.util.List; -import javax.annotation.Nonnull; -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 VPP reader, allowing read of all the elements - * - * @param Specific DataObject derived type, that is handled by this reader - */ -@Beta -public interface ListVppReader, K extends Identifier> extends VppReader { - - /** - * 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 readList(@Nonnull final InstanceIdentifier id, - @Nonnull final ReadContext ctx) throws ReadFailedException; -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/ReadContext.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/ReadContext.java deleted file mode 100644 index 6aa64b3b9..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/ReadContext.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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.impl.trans.r; - -import io.fd.honeycomb.v3po.impl.trans.util.Context; -import javax.annotation.Nonnull; - -/** - * Read Context - */ -public interface ReadContext extends AutoCloseable { - - /** - * Get key value storage for customizers - * - * @return Context for customizers - */ - @Nonnull - Context getContext(); - - @Override - void close(); -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/ReaderRegistry.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/ReaderRegistry.java deleted file mode 100644 index a1175533b..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/ReaderRegistry.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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.impl.trans.r; - -import com.google.common.annotations.Beta; -import com.google.common.collect.Multimap; -import io.fd.honeycomb.v3po.impl.trans.ReadFailedException; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Simple delegating reader suitable as a holder for all other root readers, providing readAll feature. - */ -@Beta -public interface ReaderRegistry extends VppReader { - - /** - * Performs read on all registered root readers and merges the results into a Multimap. Keys represent identifiers - * for root DataObjects from the data tree modeled by YANG. - * - * @param ctx Read context - * - * @return multimap that preserves deterministic iteration order across non-distinct key values - * @throws ReadFailedException if read was unsuccessful - */ - @Nonnull - Multimap, ? extends DataObject> readAll(@Nonnull final ReadContext ctx) - throws ReadFailedException; -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/VppReader.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/VppReader.java deleted file mode 100644 index ff42b57f0..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/VppReader.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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.impl.trans.r; - -import com.google.common.annotations.Beta; -import com.google.common.base.Optional; -import io.fd.honeycomb.v3po.impl.trans.ReadFailedException; -import io.fd.honeycomb.v3po.impl.trans.SubtreeManager; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Base VPP reader, responsible for translation between DataObjects and VPP APIs - * - * @param Specific DataObject derived type, that is handled by this reader - */ -@Beta -public interface VppReader extends SubtreeManager { - - // TODO make async - - /** - * Reads from VPP data identified by id - * - * @param id unique identifier of subtree to be read. The subtree must contain managed data object type. For - * identifiers pointing below node managed by this reader, it's reader's responsibility to filter out the - * right node or to delegate the read to a child reader. - * @param ctx Read context - * - * @return List of DataObjects identified by id. If the ID points to a single node, it will be wrapped in a list - * @throws ReadFailedException if read was unsuccessful - */ - @Nonnull - Optional read(@Nonnull final InstanceIdentifier id, - @Nonnull ReadContext ctx) throws ReadFailedException; - -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/AbstractCompositeVppReader.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/AbstractCompositeVppReader.java deleted file mode 100644 index 436aace84..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/AbstractCompositeVppReader.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * 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.impl.trans.r.impl; - -import static com.google.common.base.Preconditions.checkArgument; - -import com.google.common.annotations.Beta; -import com.google.common.base.Optional; -import com.google.common.base.Predicate; -import com.google.common.collect.Iterables; -import io.fd.honeycomb.v3po.impl.trans.ReadFailedException; -import io.fd.honeycomb.v3po.impl.trans.r.ChildVppReader; -import io.fd.honeycomb.v3po.impl.trans.r.ReadContext; -import io.fd.honeycomb.v3po.impl.trans.r.VppReader; -import io.fd.honeycomb.v3po.impl.trans.util.ReflectionUtils; -import io.fd.honeycomb.v3po.impl.trans.util.VppRWUtils; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.Augmentation; -import org.opendaylight.yangtools.yang.binding.ChildOf; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.Identifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@Beta -abstract class AbstractCompositeVppReader> implements VppReader { - - private static final Logger LOG = LoggerFactory.getLogger(AbstractCompositeVppReader.class); - - private final Map, ChildVppReader>> childReaders; - private final Map, ChildVppReader>> augReaders; - private final InstanceIdentifier instanceIdentifier; - - AbstractCompositeVppReader(final Class managedDataObjectType, - final List>> childReaders, - final List>> augReaders) { - this.childReaders = VppRWUtils.uniqueLinkedIndex(childReaders, VppRWUtils.MANAGER_CLASS_FUNCTION); - this.augReaders = VppRWUtils.uniqueLinkedIndex(augReaders, VppRWUtils.MANAGER_CLASS_AUG_FUNCTION); - this.instanceIdentifier = InstanceIdentifier.create(managedDataObjectType); - } - - @Nonnull - @Override - public final InstanceIdentifier getManagedDataObjectType() { - return instanceIdentifier; - } - - /** - * @param id {@link InstanceIdentifier} pointing to current node. In case of keyed list, key must be present. - * - */ - protected Optional readCurrent(final InstanceIdentifier id, - @Nonnull final ReadContext ctx) throws - ReadFailedException { - LOG.debug("{}: Reading current: {}", this, id); - final B builder = getBuilder(id); - // Cache empty value to determine if anything has changed later TODO cache in a field - final D emptyValue = builder.build(); - - LOG.trace("{}: Reading current attributes", this); - readCurrentAttributes(id, builder, ctx); - - // TODO expect exceptions from reader - for (ChildVppReader> child : childReaders.values()) { - LOG.debug("{}: Reading child from: {}", this, child); - child.read(id, builder, ctx); - } - - for (ChildVppReader> child : augReaders.values()) { - LOG.debug("{}: Reading augment from: {}", this, child); - child.read(id, builder, ctx); - } - - // Need to check whether anything was filled in to determine if data is present or not. - final D built = builder.build(); - final Optional read = built.equals(emptyValue) - ? Optional.absent() - : Optional.of(built); - - LOG.debug("{}: Current node read successfully. Result: {}", this, read); - return read; - } - - @Nonnull - @Override - @SuppressWarnings("unchecked") - public Optional read(@Nonnull final InstanceIdentifier id, - @Nonnull final ReadContext ctx) - throws ReadFailedException { - LOG.trace("{}: Reading : {}", this, id); - if (id.getTargetType().equals(getManagedDataObjectType().getTargetType())) { - return readCurrent((InstanceIdentifier) id, ctx); - } else { - return readSubtree(id, ctx); - } - } - - private Optional readSubtree(final InstanceIdentifier id, - @Nonnull final ReadContext ctx) - throws ReadFailedException { - LOG.debug("{}: Reading subtree: {}", this, id); - final Class next = VppRWUtils.getNextId(id, getManagedDataObjectType()).getType(); - final ChildVppReader> vppReader = childReaders.get(next); - - if (vppReader != null) { - LOG.debug("{}: Reading subtree: {} from: {}", this, id, vppReader); - return vppReader.read(id, ctx); - } else { - LOG.debug("{}: Dedicated subtree reader missing for: {}. Reading current and filtering", this, next); - // If there's no dedicated reader, use read current - final InstanceIdentifier currentId = VppRWUtils.cutId(id, getManagedDataObjectType()); - final Optional current = readCurrent(currentId, ctx); - // then perform post-reading filtering (return only requested sub-node) - final Optional readSubtree = current.isPresent() - ? filterSubtree(current.get(), id, getManagedDataObjectType().getTargetType()) - : current; - - LOG.debug("{}: Subtree: {} read successfully. Result: {}", this, id, readSubtree); - return readSubtree; - } - } - - /** - * Fill in current node's attributes - * - * @param id {@link InstanceIdentifier} pointing to current node. In case of keyed list, key must be present. - * @param builder Builder object for current node where the read attributes must be placed - * @param ctx Current read context - */ - protected abstract void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final B builder, - @Nonnull final ReadContext ctx) throws ReadFailedException; - - /** - * Return new instance of a builder object for current node - * - * @param id {@link InstanceIdentifier} pointing to current node. In case of keyed list, key must be present. - * @return Builder object for current node type - */ - protected abstract B getBuilder(InstanceIdentifier id); - - // TODO move filtering out of here into a dedicated Filter ifc - @Nonnull - private static Optional filterSubtree(@Nonnull final DataObject parent, - @Nonnull final InstanceIdentifier absolutPath, - @Nonnull final Class managedType) { - // TODO is there a better way than reflection ? e.g. convert into NN and filter out with a utility - // FIXME this needs to be recursive. right now it expects only 1 additional element in ID + test - - final InstanceIdentifier.PathArgument nextId = - VppRWUtils.getNextId(absolutPath, InstanceIdentifier.create(parent.getClass())); - - Optional method = ReflectionUtils.findMethodReflex(managedType, "get", - Collections.>emptyList(), nextId.getType()); - - if (method.isPresent()) { - return Optional.fromNullable(filterSingle(parent, nextId, method.get())); - } else { - // List child nodes - method = ReflectionUtils.findMethodReflex(managedType, - "get" + nextId.getType().getSimpleName(), Collections.>emptyList(), List.class); - - if (method.isPresent()) { - return filterList(parent, nextId, method.get()); - } else { - throw new IllegalStateException( - "Unable to filter " + nextId + " from " + parent + " getters not found using reflexion"); - } - } - } - - @SuppressWarnings("unchecked") - private static Optional filterList(final DataObject parent, - final InstanceIdentifier.PathArgument nextId, - final Method method) { - final List invoke = (List) invoke(method, nextId, parent); - - checkArgument(nextId instanceof InstanceIdentifier.IdentifiableItem, - "Unable to perform wildcarded read for %s", nextId); - final Identifier key = ((InstanceIdentifier.IdentifiableItem) nextId).getKey(); - return Iterables.tryFind(invoke, new Predicate() { - @Override - public boolean apply(@Nullable final DataObject input) { - final Optional keyGetter = - ReflectionUtils.findMethodReflex(nextId.getType(), "get", - Collections.>emptyList(), key.getClass()); - final Object actualKey; - actualKey = invoke(keyGetter.get(), nextId, input); - return key.equals(actualKey); - } - }); - } - - private static DataObject filterSingle(final DataObject parent, - final InstanceIdentifier.PathArgument nextId, final Method method) { - return nextId.getType().cast(invoke(method, nextId, parent)); - } - - private static Object invoke(final Method method, - final InstanceIdentifier.PathArgument nextId, final DataObject parent) { - try { - return method.invoke(parent); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new IllegalArgumentException("Unable to get " + nextId + " from " + parent, e); - } - } - - @Override - public String toString() { - return String.format("Reader[%s]", getManagedDataObjectType().getTargetType().getSimpleName()); - } -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/CompositeChildVppReader.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/CompositeChildVppReader.java deleted file mode 100644 index e6872d131..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/CompositeChildVppReader.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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.impl.trans.r.impl; - -import com.google.common.annotations.Beta; -import com.google.common.base.Optional; -import io.fd.honeycomb.v3po.impl.trans.ReadFailedException; -import io.fd.honeycomb.v3po.impl.trans.r.ChildVppReader; -import io.fd.honeycomb.v3po.impl.trans.r.ReadContext; -import io.fd.honeycomb.v3po.impl.trans.r.impl.spi.ChildVppReaderCustomizer; -import io.fd.honeycomb.v3po.impl.trans.util.VppRWUtils; -import java.util.List; -import javax.annotation.Nonnull; -import javax.annotation.concurrent.ThreadSafe; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.Augmentation; -import org.opendaylight.yangtools.yang.binding.ChildOf; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Composite implementation of {@link ChildVppReader} able to place the read result into - * parent builder object. - */ -@Beta -@ThreadSafe -public final class CompositeChildVppReader> extends AbstractCompositeVppReader - implements ChildVppReader { - - private final ChildVppReaderCustomizer customizer; - - /** - * Create new {@link CompositeChildVppReader} - * - * @param managedDataObjectType Class object for managed data type - * @param childReaders Child nodes(container, list) readers - * @param augReaders Child augmentations readers - * @param customizer Customizer instance to customize this generic reader - * - */ - public CompositeChildVppReader(@Nonnull final Class managedDataObjectType, - @Nonnull final List>> childReaders, - @Nonnull final List>> augReaders, - @Nonnull final ChildVppReaderCustomizer customizer) { - super(managedDataObjectType, childReaders, augReaders); - this.customizer = customizer; - } - - /** - * @see {@link CompositeChildVppReader#CompositeChildVppReader(Class, List, List, ChildVppReaderCustomizer)} - */ - public CompositeChildVppReader(@Nonnull final Class managedDataObjectType, - @Nonnull final List>> childReaders, - @Nonnull final ChildVppReaderCustomizer customizer) { - this(managedDataObjectType, childReaders, VppRWUtils.emptyAugReaderList(), customizer); - } - - /** - * @see {@link CompositeChildVppReader#CompositeChildVppReader(Class, List, List, ChildVppReaderCustomizer)} - */ - public CompositeChildVppReader(@Nonnull final Class managedDataObjectType, - @Nonnull final ChildVppReaderCustomizer customizer) { - this(managedDataObjectType, VppRWUtils.emptyChildReaderList(), VppRWUtils.emptyAugReaderList(), - customizer); - } - - @Override - public final void read(@Nonnull final InstanceIdentifier parentId, - @Nonnull final Builder parentBuilder, - @Nonnull final ReadContext ctx) throws ReadFailedException { - final Optional read = readCurrent(VppRWUtils.appendTypeToId(parentId, getManagedDataObjectType()), ctx); - - if(read.isPresent()) { - customizer.merge(parentBuilder, read.get()); - } - } - - @Override - protected void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final B builder, - @Nonnull final ReadContext ctx) - throws ReadFailedException { - customizer.readCurrentAttributes(id, builder, ctx.getContext()); - } - - @Override - protected B getBuilder(@Nonnull final InstanceIdentifier id) { - return customizer.getBuilder(id); - } - -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/CompositeListVppReader.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/CompositeListVppReader.java deleted file mode 100644 index 9d7ad3446..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/CompositeListVppReader.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * 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.impl.trans.r.impl; - -import static com.google.common.base.Preconditions.checkArgument; - -import com.google.common.annotations.Beta; -import com.google.common.base.Optional; -import io.fd.honeycomb.v3po.impl.trans.ReadFailedException; -import io.fd.honeycomb.v3po.impl.trans.r.ChildVppReader; -import io.fd.honeycomb.v3po.impl.trans.r.ListVppReader; -import io.fd.honeycomb.v3po.impl.trans.r.ReadContext; -import io.fd.honeycomb.v3po.impl.trans.r.impl.spi.ListVppReaderCustomizer; -import io.fd.honeycomb.v3po.impl.trans.util.VppRWUtils; -import java.util.ArrayList; -import java.util.List; -import javax.annotation.Nonnull; -import javax.annotation.concurrent.ThreadSafe; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.Augmentation; -import org.opendaylight.yangtools.yang.binding.ChildOf; -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.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Composite implementation of {@link ChildVppReader} able to place the read result into parent builder object intended - * for list node type. - * - * This reader checks if the IDs are wildcarded in which case it performs read of all list entries. In case the ID has a - * key, it reads only the specified value. - */ -@Beta -@ThreadSafe -public final class CompositeListVppReader, K extends Identifier, B extends Builder> - extends AbstractCompositeVppReader implements ChildVppReader, ListVppReader { - - private static final Logger LOG = LoggerFactory.getLogger(CompositeListVppReader.class); - - private final ListVppReaderCustomizer customizer; - - /** - * Create new {@link CompositeListVppReader} - * - * @param managedDataObjectType Class object for managed data type. Must come from a list node type. - * @param childReaders Child nodes(container, list) readers - * @param augReaders Child augmentations readers - * @param customizer Customizer instance to customize this generic reader - */ - public CompositeListVppReader(@Nonnull final Class managedDataObjectType, - @Nonnull final List>> childReaders, - @Nonnull final List>> augReaders, - @Nonnull final ListVppReaderCustomizer customizer) { - super(managedDataObjectType, childReaders, augReaders); - this.customizer = customizer; - } - - /** - * @see {@link CompositeListVppReader#CompositeListVppReader(Class, List, List, ListVppReaderCustomizer)} - */ - public CompositeListVppReader(@Nonnull final Class managedDataObjectType, - @Nonnull final List>> childReaders, - @Nonnull final ListVppReaderCustomizer customizer) { - this(managedDataObjectType, childReaders, VppRWUtils.emptyAugReaderList(), customizer); - } - - /** - * @see {@link CompositeListVppReader#CompositeListVppReader(Class, List, List, ListVppReaderCustomizer)} - */ - public CompositeListVppReader(@Nonnull final Class managedDataObjectType, - @Nonnull final ListVppReaderCustomizer customizer) { - this(managedDataObjectType, VppRWUtils.emptyChildReaderList(), VppRWUtils.emptyAugReaderList(), - customizer); - } - - @Override - public void read(@Nonnull final InstanceIdentifier id, - @Nonnull final Builder parentBuilder, - @Nonnull final ReadContext ctx) throws ReadFailedException { - // Create ID pointing to current node - final InstanceIdentifier currentId = VppRWUtils.appendTypeToId(id, getManagedDataObjectType()); - // Read all, since current ID is definitely wildcarded - final List ifcs = readList(currentId, ctx); - customizer.merge(parentBuilder, ifcs); - } - - @Override - @Nonnull - public List readList(@Nonnull final InstanceIdentifier id, - @Nonnull final ReadContext ctx) throws ReadFailedException { - LOG.trace("{}: Reading all list entries", this); - final List allIds = customizer.getAllIds(id, ctx.getContext()); - LOG.debug("{}: Reading list entries for: {}", this, allIds); - - final ArrayList allEntries = new ArrayList<>(allIds.size()); - for (K key : allIds) { - final InstanceIdentifier.IdentifiableItem currentBdItem = - VppRWUtils.getCurrentIdItem(id, key); - final InstanceIdentifier keyedId = VppRWUtils.replaceLastInId(id, currentBdItem); - final Optional read = readCurrent(keyedId, ctx); - final DataObject singleItem = read.get(); - checkArgument(getManagedDataObjectType().getTargetType().isAssignableFrom(singleItem.getClass())); - allEntries.add(getManagedDataObjectType().getTargetType().cast(singleItem)); - } - return allEntries; - } - - @Override - protected void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final B builder, - @Nonnull final ReadContext ctx) - throws ReadFailedException { - customizer.readCurrentAttributes(id, builder, ctx.getContext()); - } - - @Override - protected B getBuilder(@Nonnull final InstanceIdentifier id) { - return customizer.getBuilder(id); - } - -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/CompositeRootVppReader.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/CompositeRootVppReader.java deleted file mode 100644 index 34d4dce74..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/CompositeRootVppReader.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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.impl.trans.r.impl; - -import com.google.common.annotations.Beta; -import io.fd.honeycomb.v3po.impl.trans.ReadFailedException; -import io.fd.honeycomb.v3po.impl.trans.r.ChildVppReader; -import io.fd.honeycomb.v3po.impl.trans.r.ReadContext; -import io.fd.honeycomb.v3po.impl.trans.r.VppReader; -import io.fd.honeycomb.v3po.impl.trans.r.impl.spi.RootVppReaderCustomizer; -import io.fd.honeycomb.v3po.impl.trans.util.VppRWUtils; -import java.util.List; -import javax.annotation.Nonnull; -import javax.annotation.concurrent.ThreadSafe; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.Augmentation; -import org.opendaylight.yangtools.yang.binding.ChildOf; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Composite implementation of {@link VppReader} - */ -@Beta -@ThreadSafe -public final class CompositeRootVppReader> extends AbstractCompositeVppReader - implements VppReader { - - private final RootVppReaderCustomizer customizer; - - /** - * Create new {@link CompositeRootVppReader} - * - * @param managedDataObjectType Class object for managed data type - * @param childReaders Child nodes(container, list) readers - * @param augReaders Child augmentations readers - * @param customizer Customizer instance to customize this generic reader - * - */ - public CompositeRootVppReader(@Nonnull final Class managedDataObjectType, - @Nonnull final List>> childReaders, - @Nonnull final List>> augReaders, - @Nonnull final RootVppReaderCustomizer customizer) { - super(managedDataObjectType, childReaders, augReaders); - this.customizer = customizer; - } - - /** - * @see {@link CompositeRootVppReader#CompositeRootVppReader(Class, List, List, RootVppReaderCustomizer)} - */ - public CompositeRootVppReader(@Nonnull final Class managedDataObjectType, - @Nonnull final List>> childReaders, - @Nonnull final RootVppReaderCustomizer customizer) { - this(managedDataObjectType, childReaders, VppRWUtils.emptyAugReaderList(), customizer); - } - - /** - * @see {@link CompositeRootVppReader#CompositeRootVppReader(Class, List, List, RootVppReaderCustomizer)} - */ - public CompositeRootVppReader(@Nonnull final Class managedDataObjectType, - @Nonnull final RootVppReaderCustomizer customizer) { - this(managedDataObjectType, VppRWUtils.emptyChildReaderList(), VppRWUtils.emptyAugReaderList(), - customizer); - } - - @Override - protected void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final B builder, - @Nonnull final ReadContext ctx) - throws ReadFailedException { - customizer.readCurrentAttributes(id, builder, ctx.getContext()); - } - - @Override - protected B getBuilder(@Nonnull final InstanceIdentifier id) { - return customizer.getBuilder(id); - } - -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/spi/ChildVppReaderCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/spi/ChildVppReaderCustomizer.java deleted file mode 100644 index 900f8f8c6..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/spi/ChildVppReaderCustomizer.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.impl.trans.r.impl.spi; - -import com.google.common.annotations.Beta; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; - -/** - * {@link io.fd.honeycomb.v3po.impl.trans.r.impl.CompositeChildVppReader} SPI to customize its behavior - * - * @param Specific DataObject derived type (Identifiable), that is handled by this customizer - * @param Specific Builder for handled type (C) - */ -@Beta -public interface ChildVppReaderCustomizer> extends - RootVppReaderCustomizer { - - // FIXME need to capture parent builder type, but that's inconvenient at best, is it ok to leave it Builder and - // cast in specific customizers ? ... probably better than adding another type parameter - - /** - * Merge read data into provided parent builder - */ - void merge(@Nonnull final Builder parentBuilder, @Nonnull final C readValue); -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/spi/ListVppReaderCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/spi/ListVppReaderCustomizer.java deleted file mode 100644 index c87050bd6..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/spi/ListVppReaderCustomizer.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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.impl.trans.r.impl.spi; - -import com.google.common.annotations.Beta; -import io.fd.honeycomb.v3po.impl.trans.util.Context; -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; - -/** - * {@link io.fd.honeycomb.v3po.impl.trans.r.impl.CompositeListVppReader} SPI to customize its behavior - * - * @param Specific DataObject derived type (Identifiable), that is handled by this customizer - * @param Specific Identifier for handled type (C) - * @param Specific Builder for handled type (C) - */ -@Beta -public interface ListVppReaderCustomizer, K extends Identifier, B extends Builder> - extends RootVppReaderCustomizer { - - /** - * Return list with IDs of all list nodes to be read. - * - * @param id Wildcarded ID pointing to list node managed by enclosing reader - * @param context Read context - */ - @Nonnull - List getAllIds(@Nonnull final InstanceIdentifier id, @Nonnull final Context context); - // TODO does it make sense with vpp APIs ? Should we replace it with a simple readAll ? - - /** - * Merge read data into provided parent builder - */ - void merge(@Nonnull final Builder builder, @Nonnull final List readData); -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/spi/RootVppReaderCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/spi/RootVppReaderCustomizer.java deleted file mode 100644 index b35a1c66c..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/spi/RootVppReaderCustomizer.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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.impl.trans.r.impl.spi; - -import com.google.common.annotations.Beta; -import io.fd.honeycomb.v3po.impl.trans.ReadFailedException; -import io.fd.honeycomb.v3po.impl.trans.util.Context; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * {@link io.fd.honeycomb.v3po.impl.trans.r.impl.CompositeRootVppReader} SPI to customize its behavior - * - * @param Specific DataObject derived type, that is handled by this customizer - * @param Specific Builder for handled type (C) - */ -@Beta -public interface RootVppReaderCustomizer> { - - /** - * Creates new builder that will be used to build read value. - */ - @Nonnull - B getBuilder(@Nonnull final InstanceIdentifier id); - - - /** - * Adds current data (identified by id) to the provided builder. - * - * @param id id of current data object - * @param builder builder for creating read value - * @throws ReadFailedException if read was unsuccessful - */ - void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final B builder, - @Nonnull final Context ctx) throws ReadFailedException; -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/util/DelegatingReaderRegistry.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/util/DelegatingReaderRegistry.java deleted file mode 100644 index 51334e6db..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/util/DelegatingReaderRegistry.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * 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.impl.trans.r.util; - -import static com.google.common.base.Preconditions.checkNotNull; - -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 io.fd.honeycomb.v3po.impl.trans.ReadFailedException; -import io.fd.honeycomb.v3po.impl.trans.r.ListVppReader; -import io.fd.honeycomb.v3po.impl.trans.r.ReadContext; -import io.fd.honeycomb.v3po.impl.trans.r.ReaderRegistry; -import io.fd.honeycomb.v3po.impl.trans.r.VppReader; -import io.fd.honeycomb.v3po.impl.trans.util.VppRWUtils; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Simple reader registry able to perform and aggregated read (ROOT read) on top of all provided readers. Also able to - * delegate a specific read to one of the delegate readers. - * - * This could serve as a utility to hold & hide all available readers in upper layers. - */ -public final class DelegatingReaderRegistry implements ReaderRegistry { - - private static final Logger LOG = LoggerFactory.getLogger(DelegatingReaderRegistry.class); - - private final Map, VppReader> rootReaders; - - /** - * Create new {@link DelegatingReaderRegistry} - * - * @param rootReaders List of delegate readers - */ - public DelegatingReaderRegistry(@Nonnull final List> rootReaders) { - this.rootReaders = VppRWUtils.uniqueLinkedIndex(checkNotNull(rootReaders), VppRWUtils.MANAGER_CLASS_FUNCTION); - } - - @Override - @Nonnull - public Multimap, ? extends DataObject> readAll( - @Nonnull final ReadContext ctx) throws ReadFailedException { - - LOG.debug("Reading from all delegates: {}", this); - LOG.trace("Reading from all delegates: {}", rootReaders.values()); - - final Multimap, DataObject> objects = LinkedListMultimap.create(); - for (VppReader rootReader : rootReaders.values()) { - LOG.debug("Reading from delegate: {}", rootReader); - - if (rootReader instanceof ListVppReader) { - final List listEntries = - ((ListVppReader) rootReader).readList(rootReader.getManagedDataObjectType(), ctx); - if (!listEntries.isEmpty()) { - objects.putAll(rootReader.getManagedDataObjectType(), listEntries); - } - } else { - final Optional read = rootReader.read(rootReader.getManagedDataObjectType(), ctx); - if (read.isPresent()) { - objects.putAll(rootReader.getManagedDataObjectType(), Collections.singletonList(read.get())); - } - } - } - - return objects; - } - - @Nonnull - @Override - public Optional read(@Nonnull final InstanceIdentifier id, - @Nonnull final ReadContext ctx) - throws ReadFailedException { - final InstanceIdentifier.PathArgument first = checkNotNull( - Iterables.getFirst(id.getPathArguments(), null), "Empty id"); - final VppReader vppReader = rootReaders.get(first.getType()); - checkNotNull(vppReader, - "Unable to read %s. Missing reader. Current readers for: %s", id, rootReaders.keySet()); - LOG.debug("Reading from delegate: {}", vppReader); - return vppReader.read(id, ctx); - } - - /** - * @throws UnsupportedOperationException This getter is not supported for reader registry since it does not manage a - * specific node type - */ - @Nonnull - @Override - public InstanceIdentifier getManagedDataObjectType() { - throw new UnsupportedOperationException("Root registry has no type"); - } -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/util/NoopReaderCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/util/NoopReaderCustomizer.java deleted file mode 100644 index 657af97f4..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/util/NoopReaderCustomizer.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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.impl.trans.r.util; - -import io.fd.honeycomb.v3po.impl.trans.r.impl.spi.RootVppReaderCustomizer; -import io.fd.honeycomb.v3po.impl.trans.util.Context; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -public abstract class NoopReaderCustomizer> implements RootVppReaderCustomizer { - - @Override - public void readCurrentAttributes(InstanceIdentifier id, final B builder, final Context context) { - // Noop - } -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/util/ReflexiveChildReaderCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/util/ReflexiveChildReaderCustomizer.java deleted file mode 100644 index 6eb7ef576..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/util/ReflexiveChildReaderCustomizer.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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.impl.trans.r.util; - -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -import io.fd.honeycomb.v3po.impl.trans.r.impl.spi.ChildVppReaderCustomizer; -import io.fd.honeycomb.v3po.impl.trans.util.ReflectionUtils; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Collections; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; - -/** - * Might be slow ! - */ -public class ReflexiveChildReaderCustomizer> - extends ReflexiveRootReaderCustomizer - implements ChildVppReaderCustomizer { - - public ReflexiveChildReaderCustomizer(final Class builderClass) { - super(builderClass); - } - - // TODO Could be just a default implementation in interface (making this a mixin) - - @Override - public void merge(final Builder parentBuilder, final C readValue) { - final Optional method = - ReflectionUtils.findMethodReflex(parentBuilder.getClass(), "set", - Collections.>singletonList(readValue.getClass()), parentBuilder.getClass()); - - Preconditions.checkArgument(method.isPresent(), "Unable to set %s to %s", readValue, parentBuilder); - - try { - method.get().invoke(parentBuilder, readValue); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new IllegalArgumentException("Unable to set " + readValue + " to " + parentBuilder, e); - } - } - -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/util/ReflexiveRootReaderCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/util/ReflexiveRootReaderCustomizer.java deleted file mode 100644 index b1f776c01..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/util/ReflexiveRootReaderCustomizer.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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.impl.trans.r.util; - -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Might be slow ! - */ -public class ReflexiveRootReaderCustomizer> extends NoopReaderCustomizer { - - private final Class builderClass; - - public ReflexiveRootReaderCustomizer(final Class builderClass) { - this.builderClass = builderClass; - } - - @Override - public B getBuilder(InstanceIdentifier id) { - try { - return builderClass.newInstance(); - } catch (InstantiationException | IllegalAccessException e) { - throw new IllegalStateException("Unable to instantiate " + builderClass, e); - } - } -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/Context.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/Context.java deleted file mode 100644 index 089d22957..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/Context.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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.impl.trans.util; - -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 Context implements AutoCloseable { - - protected final HashMap map; - - public Context() { - 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/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/ReflectionUtils.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/ReflectionUtils.java deleted file mode 100644 index 6602d750d..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/ReflectionUtils.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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.impl.trans.util; - -import com.google.common.base.Optional; -import java.lang.reflect.Method; -import java.util.List; -import javax.annotation.Nonnull; - -/** - * Reflection based utilities - */ -public final class ReflectionUtils { - - private ReflectionUtils() {} - - /** - * Find a specific method using reflection - * - * @param managedType Class object to find method in - * @param prefix Method name prefix used when finding the method. Case does not matter. - * @param paramTypes List of input argument types - * @param retType Return type - * - * @return Found method or Optional.absent() if there's no such method - */ - @Nonnull - public static Optional findMethodReflex(@Nonnull final Class managedType, - @Nonnull final String prefix, - @Nonnull final List> paramTypes, - @Nonnull final Class retType) { - for (Method method : managedType.getMethods()) { - if(isMethodMatch(prefix, paramTypes, retType, method)) { - return Optional.of(method); - } - } - - return Optional.absent(); - } - - private static boolean isMethodMatch(final @Nonnull String prefix, - final @Nonnull List> paramTypes, - final @Nonnull Class retType, final Method method) { - if (!method.getName().toLowerCase().startsWith(prefix.toLowerCase())) { - return false; - } - - final Class[] parameterTypes = method.getParameterTypes(); - if (parameterTypes.length != paramTypes.size()) { - return false; - } - - for (int i = 0; i < parameterTypes.length; i++) { - if (!parameterTypes[i].isAssignableFrom(paramTypes.get(i))) { - return false; - } - } - - if (!method.getReturnType().equals(retType)) { - return false; - } - - return true; - } -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/VppApiCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/VppApiCustomizer.java deleted file mode 100644 index f33dd988e..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/VppApiCustomizer.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.impl.trans.util; - -import com.google.common.annotations.Beta; - -/** - * Abstract utility to hold the vppApi reference. - */ -@Beta -public abstract class VppApiCustomizer { - - private final org.openvpp.vppjapi.vppApi vppApi; - - protected VppApiCustomizer(final org.openvpp.vppjapi.vppApi vppApi) { - this.vppApi = vppApi; - } - - /** - * Get vppApi reference - * - * @return vppApi reference - */ - public org.openvpp.vppjapi.vppApi getVppApi() { - return vppApi; - } -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/VppRWUtils.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/VppRWUtils.java deleted file mode 100644 index d11910b6f..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/util/VppRWUtils.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * 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.impl.trans.util; - -import com.google.common.base.Function; -import com.google.common.base.Preconditions; -import com.google.common.base.Predicate; -import com.google.common.collect.Iterables; -import com.google.common.collect.Maps; -import io.fd.honeycomb.v3po.impl.trans.SubtreeManager; -import io.fd.honeycomb.v3po.impl.trans.r.ChildVppReader; -import io.fd.honeycomb.v3po.impl.trans.w.ChildVppWriter; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.Augmentation; -import org.opendaylight.yangtools.yang.binding.ChildOf; -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; - -public final class VppRWUtils { - - private VppRWUtils() {} - - /** - * Find next item in ID after provided type - */ - @Nonnull - public static InstanceIdentifier.PathArgument getNextId(@Nonnull final InstanceIdentifier id, - @Nonnull final InstanceIdentifier type) { - // TODO this is inefficient(maybe, depending on actual Iterable type) - final Iterable pathArguments = id.getPathArguments(); - final int i = Iterables.indexOf(pathArguments, new Predicate() { - @Override - public boolean apply(final InstanceIdentifier.PathArgument input) { - return input.getType().isAssignableFrom(type.getTargetType()); - } - }); - Preconditions.checkArgument(i >= 0, "Unable to find %s type in %s", type.getTargetType(), id); - return Iterables.get(pathArguments, i + 1); - } - - public static List>> emptyChildReaderList() { - return Collections.emptyList(); - } - - public static List>> emptyChildWriterList() { - return Collections.emptyList(); - } - - public static List>> emptyAugReaderList() { - return Collections.emptyList(); - } - - public static List>> emptyAugWriterList() { - return Collections.emptyList(); - } - - public static List>> singletonAugReaderList( - ChildVppReader> item) { - return Collections.>>singletonList(item); - } - - public static List>> singletonChildReaderList( - ChildVppReader> item) { - return Collections.>>singletonList(item); - } - - public static List>> singletonChildWriterList( - ChildVppWriter> item) { - return Collections.>>singletonList(item); - } - - /** - * Replace last item in ID with a provided IdentifiableItem of the same type - */ - @SuppressWarnings("unchecked") - @Nonnull - public static , K extends Identifier> InstanceIdentifier replaceLastInId( - @Nonnull final InstanceIdentifier id, final InstanceIdentifier.IdentifiableItem currentBdItem) { - - final Iterable pathArguments = id.getPathArguments(); - final Iterable withoutCurrent = - Iterables.limit(pathArguments, Iterables.size(pathArguments) - 1); - final Iterable concat = - Iterables.concat(withoutCurrent, Collections.singleton(currentBdItem)); - return (InstanceIdentifier) InstanceIdentifier.create(concat); - } - - /** - * Create IdentifiableItem from target type of provided ID with provided key - */ - @Nonnull - public static , K extends Identifier> InstanceIdentifier.IdentifiableItem getCurrentIdItem( - @Nonnull final InstanceIdentifier id, final K key) { - return new InstanceIdentifier.IdentifiableItem<>(id.getTargetType(), key); - } - - /** - * Trim InstanceIdentifier at indexOf(type) - */ - @SuppressWarnings("unchecked") - @Nonnull - public static InstanceIdentifier cutId(@Nonnull final InstanceIdentifier id, - @Nonnull final InstanceIdentifier type) { - final Iterable pathArguments = id.getPathArguments(); - final int i = Iterables.indexOf(pathArguments, new Predicate() { - @Override - public boolean apply(final InstanceIdentifier.PathArgument input) { - return input.getType().equals(type.getTargetType()); - } - }); - Preconditions.checkArgument(i >= 0, "ID %s does not contain %s", id, type); - return (InstanceIdentifier) InstanceIdentifier.create(Iterables.limit(pathArguments, i + 1)); - } - - /** - * Create a map from a collection, checking for duplicity in the process - */ - @Nonnull - public static Map uniqueLinkedIndex(@Nonnull final Collection values, @Nonnull final Function keyFunction) { - final Map objectObjectLinkedHashMap = Maps.newLinkedHashMap(); - for (V value : values) { - final K key = keyFunction.apply(value); - Preconditions.checkArgument(objectObjectLinkedHashMap.put(key, value) == null, - "Duplicate key detected : %s", key); - } - return objectObjectLinkedHashMap; - } - - public static final Function, Class> - MANAGER_CLASS_FUNCTION = new Function, Class>() { - @Override - public Class apply(final SubtreeManager input) { - return input.getManagedDataObjectType().getTargetType(); - } - }; - - public static final Function>, Class> - MANAGER_CLASS_AUG_FUNCTION = new Function>, Class>() { - - @Override - @SuppressWarnings("unchecked") - public Class apply(final SubtreeManager> input) { - final Class> targetType = input.getManagedDataObjectType().getTargetType(); - Preconditions.checkArgument(DataObject.class.isAssignableFrom(targetType)); - return (Class) targetType; - } - }; - - @SuppressWarnings("unchecked") - public static InstanceIdentifier appendTypeToId( - final InstanceIdentifier parentId, final InstanceIdentifier type) { - Preconditions.checkArgument(!parentId.contains(type), - "Unexpected InstanceIdentifier %s, already contains %s", parentId, type); - final InstanceIdentifier.PathArgument t = Iterables.getOnlyElement(type.getPathArguments()); - return (InstanceIdentifier) InstanceIdentifier.create(Iterables.concat( - parentId.getPathArguments(), Collections.singleton(t))); - } -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/ChildVppWriter.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/ChildVppWriter.java deleted file mode 100644 index 243a6528d..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/ChildVppWriter.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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.impl.trans.w; - -import com.google.common.annotations.Beta; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Child VPP writer allowing its parent to pass the builder object - * - * @param Specific DataObject derived type, that is handled by this writer - */ -@Beta -public interface ChildVppWriter extends VppWriter { - - /** - * Extract data object managed by this writer from parent data and perform write. - * - * @param parentId Id of parent node - * @param parentDataAfter Parent data from modification to extract data object from - * @param ctx Write context for current modification - */ - void writeChild(@Nonnull final InstanceIdentifier parentId, - @Nonnull final DataObject parentDataAfter, - @Nonnull final WriteContext ctx); - - /** - * Extract data object managed by this writer(if necessary) from parent data and perform delete. - * - * @param parentId Id of parent node - * @param parentDataBefore Parent data before modification to extract data object from - * @param ctx Write context for current modification - */ - void deleteChild(@Nonnull final InstanceIdentifier parentId, - @Nonnull final DataObject parentDataBefore, - @Nonnull final WriteContext ctx); - - /** - * Extract data object managed by this writer(if necessary) from parent data and perform delete. - * - * @param parentId Id of parent node - * @param parentDataBefore Parent data before modification to extract data object from - * @param parentDataAfter Parent data from modification to extract data object from - * @param ctx Write context for current modification - */ - void updateChild(@Nonnull final InstanceIdentifier parentId, - @Nonnull final DataObject parentDataBefore, - @Nonnull final DataObject parentDataAfter, - @Nonnull final WriteContext ctx); -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/VppWriter.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/VppWriter.java deleted file mode 100644 index d338fafa2..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/VppWriter.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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.impl.trans.w; - -import com.google.common.annotations.Beta; -import io.fd.honeycomb.v3po.impl.trans.SubtreeManager; -import io.fd.honeycomb.v3po.impl.trans.VppException; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Base VPP writer, responsible for translation between DataObjects and VPP APIs. Handling all update operations(create, - * update, delete) - * - * @param Specific DataObject derived type, that is handled by this writer - */ -@Beta -public interface VppWriter extends SubtreeManager { - - /** - * Handle update operation. U from CRUD. - * - * @param id Identifier(from root) of data being written - * @param dataBefore Old data - * @param dataAfter New, updated data - * @param ctx Write context enabling writer to get information about candidate data as well as current data - * @throws VppException if update failed - */ - void update(@Nonnull final InstanceIdentifier id, - @Nullable final DataObject dataBefore, - @Nullable final DataObject dataAfter, - @Nonnull final WriteContext ctx) throws VppException; -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/WriteContext.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/WriteContext.java deleted file mode 100644 index 191fdf857..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/WriteContext.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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.impl.trans.w; - -import com.google.common.annotations.Beta; -import com.google.common.base.Optional; -import io.fd.honeycomb.v3po.impl.trans.util.Context; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Context providing information about current state of DataTree to writers - */ -@Beta -public interface WriteContext extends AutoCloseable { - - /** - * Read any data object before current modification was applied - * - * @param currentId Id of an object to read - * - * @return Data before the modification was applied - */ - Optional readBefore(@Nonnull final InstanceIdentifier currentId); - - /** - * Read any data object from current modification - * - * @param currentId Id of an object to read - * - * @return Data from the modification - */ - Optional readAfter(@Nonnull final InstanceIdentifier currentId); - - /** - * Get key value storage for customizers - * - * @return Context for customizers - */ - @Nonnull - Context getContext(); - - @Override - void close(); -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/WriterRegistry.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/WriterRegistry.java deleted file mode 100644 index 26c294b30..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/WriterRegistry.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * 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.impl.trans.w; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.annotations.Beta; -import com.google.common.collect.ImmutableList; -import io.fd.honeycomb.v3po.impl.trans.VppException; -import java.util.List; -import java.util.Map; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Special {@link VppWriter} capable of performing bulk updates - */ -@Beta -public interface WriterRegistry extends VppWriter { - - /** - * Performs bulk update - * - * @throws BulkUpdateException in case bulk update fails - * @throws VppException in case some other error occurs while processing update request - */ - void update(@Nonnull final Map, DataObject> dataBefore, - @Nonnull final Map, DataObject> dataAfter, - @Nonnull final WriteContext ctx) throws VppException; - - /** - * Thrown when bulk update failed. - */ - @Beta - class BulkUpdateException extends VppException { - - private final Reverter reverter; - private final InstanceIdentifier failedId; // TODO change to VppDataModification - - /** - * Constructs an BulkUpdateException. - * - * @param failedId instance identifier of the data object that caused bulk update to fail. - * @param cause the cause of bulk update failure - */ - public BulkUpdateException(@Nonnull final InstanceIdentifier failedId, @Nonnull final Reverter reverter, - final Throwable cause) { - super("Bulk update failed at " + failedId, cause); - this.failedId = checkNotNull(failedId, "failedId should not be null"); - this.reverter = checkNotNull(reverter, "reverter should not be null"); - } - - /** - * Reverts changes that were successfully applied during bulk update before failure occurred. - * - * @throws Reverter.RevertFailedException if revert fails - */ - public void revertChanges() throws Reverter.RevertFailedException { - reverter.revert(); - } - - /** - * Returns instance identifier of the data object that caused bulk update to fail. - * - * @return data object's instance identifier - */ - @Nonnull - public InstanceIdentifier getFailedId() { - return failedId; - } - } - - /** - * Abstraction over revert mechanism in cast of a bulk update failure - */ - @Beta - interface Reverter { - - /** - * Reverts changes that were successfully applied during bulk update before failure occurred. Changes are - * reverted in reverse order they were applied. - * - * @throws RevertFailedException if not all of applied changes were successfully reverted - */ - void revert() throws RevertFailedException; - - /** - * Thrown when some of the changes applied during bulk update were not reverted. - */ - @Beta - class RevertFailedException extends VppException { - - // TODO change to list of VppDataModifications to make debugging easier - private final List> notRevertedChanges; - - /** - * Constructs an RevertFailedException with the list of changes that were not reverted. - * - * @param notRevertedChanges list of changes that were not reverted - * @param cause the cause of revert failure - */ - public RevertFailedException(@Nonnull final List> notRevertedChanges, - final Throwable cause) { - super(cause); - checkNotNull(notRevertedChanges, "notRevertedChanges should not be null"); - this.notRevertedChanges = ImmutableList.copyOf(notRevertedChanges); - } - - /** - * Returns the list of changes that were not reverted. - * - * @return list of changes that were not reverted - */ - @Nonnull - public List> getNotRevertedChanges() { - return notRevertedChanges; - } - } - } -} \ No newline at end of file diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/impl/AbstractCompositeVppWriter.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/impl/AbstractCompositeVppWriter.java deleted file mode 100644 index 6e8f8bc85..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/impl/AbstractCompositeVppWriter.java +++ /dev/null @@ -1,270 +0,0 @@ -/* - * 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.impl.trans.w.impl; - -import static com.google.common.base.Preconditions.checkArgument; - -import com.google.common.base.Optional; -import com.google.common.collect.Lists; -import io.fd.honeycomb.v3po.impl.trans.VppException; -import io.fd.honeycomb.v3po.impl.trans.util.VppRWUtils; -import io.fd.honeycomb.v3po.impl.trans.w.ChildVppWriter; -import io.fd.honeycomb.v3po.impl.trans.w.VppWriter; -import io.fd.honeycomb.v3po.impl.trans.w.WriteContext; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.opendaylight.yangtools.yang.binding.Augmentation; -import org.opendaylight.yangtools.yang.binding.ChildOf; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public abstract class AbstractCompositeVppWriter implements VppWriter { - - private static final Logger LOG = LoggerFactory.getLogger(AbstractCompositeVppWriter.class); - - private final Map, ChildVppWriter>> childWriters; - private final Map, ChildVppWriter>> augWriters; - private final InstanceIdentifier instanceIdentifier; - - public AbstractCompositeVppWriter(final Class type, - final List>> childWriters, - final List>> augWriters) { - this.instanceIdentifier = InstanceIdentifier.create(type); - this.childWriters = VppRWUtils.uniqueLinkedIndex(childWriters, VppRWUtils.MANAGER_CLASS_FUNCTION); - this.augWriters = VppRWUtils.uniqueLinkedIndex(augWriters, VppRWUtils.MANAGER_CLASS_AUG_FUNCTION); - } - - protected void writeCurrent(final InstanceIdentifier id, final D data, final WriteContext ctx) { - LOG.debug("{}: Writing current: {} data: {}", this, id, data); - - LOG.trace("{}: Writing current attributes", this); - writeCurrentAttributes(id, data, ctx); - - for (ChildVppWriter> child : childWriters.values()) { - LOG.debug("{}: Writing child in: {}", this, child); - child.writeChild(id, data, ctx); - } - - for (ChildVppWriter> child : augWriters.values()) { - LOG.debug("{}: Writing augment in: {}", this, child); - child.writeChild(id, data, ctx); - } - - LOG.debug("{}: Current node written successfully", this); - } - - protected void updateCurrent(final InstanceIdentifier id, final D dataBefore, final D dataAfter, - final WriteContext ctx) { - LOG.debug("{}: Updating current: {} dataBefore: {}, datAfter: {}", this, id, dataBefore, dataAfter); - - if(dataBefore.equals(dataAfter)) { - LOG.debug("{}: Skipping current(no update): {}", this, id); - // No change, ignore - return; - } - - LOG.trace("{}: Updating current attributes", this); - updateCurrentAttributes(id, dataBefore, dataAfter, ctx); - - for (ChildVppWriter> child : childWriters.values()) { - LOG.debug("{}: Updating child in: {}", this, child); - child.updateChild(id, dataBefore, dataAfter, ctx); - } - - for (ChildVppWriter> child : augWriters.values()) { - LOG.debug("{}: Updating augment in: {}", this, child); - child.updateChild(id, dataBefore, dataAfter, ctx); - } - - LOG.debug("{}: Current node updated successfully", this); - } - - protected void deleteCurrent(final InstanceIdentifier id, final D dataBefore, final WriteContext ctx) { - LOG.debug("{}: Deleting current: {} dataBefore: {}", this, id, dataBefore); - - // delete in reversed order - for (ChildVppWriter> child : reverseCollection(augWriters.values())) { - LOG.debug("{}: Deleting augment in: {}", this, child); - child.deleteChild(id, dataBefore, ctx); - } - - for (ChildVppWriter> child : reverseCollection(childWriters.values())) { - LOG.debug("{}: Deleting child in: {}", this, child); - child.deleteChild(id, dataBefore, ctx); - } - - LOG.trace("{}: Deleting current attributes", this); - deleteCurrentAttributes(id, dataBefore, ctx); - } - - @SuppressWarnings("unchecked") - @Override - public void update(@Nonnull final InstanceIdentifier id, - @Nullable final DataObject dataBefore, - @Nullable final DataObject dataAfter, - @Nonnull final WriteContext ctx) throws VppException { - LOG.debug("{}: Updating : {}", this, id); - LOG.trace("{}: Updating : {}, from: {} to: {}", this, id, dataBefore, dataAfter); - - if (idPointsToCurrent(id)) { - if(isWrite(dataBefore, dataAfter)) { - writeCurrent((InstanceIdentifier) id, castToManaged(dataAfter), ctx); - } else if(isDelete(dataBefore, dataAfter)) { - deleteCurrent((InstanceIdentifier) id, castToManaged(dataBefore), ctx); - } else { - checkArgument(dataBefore != null && dataAfter != null, "No data to process"); - updateCurrent((InstanceIdentifier) id, castToManaged(dataBefore), castToManaged(dataAfter), ctx); - } - } else { - if (isWrite(dataBefore, dataAfter)) { - writeSubtree(id, dataAfter, ctx); - } else if (isDelete(dataBefore, dataAfter)) { - deleteSubtree(id, dataBefore, ctx); - } else { - checkArgument(dataBefore != null && dataAfter != null, "No data to process"); - updateSubtree(id, dataBefore, dataAfter, ctx); - } - } - } - - private void checkDataType(final @Nullable DataObject dataAfter) { - checkArgument(getManagedDataObjectType().getTargetType().isAssignableFrom(dataAfter.getClass())); - } - - private D castToManaged(final DataObject data) { - checkDataType(data); - return getManagedDataObjectType().getTargetType().cast(data); - } - - private static boolean isWrite(final DataObject dataBefore, - final DataObject dataAfter) { - return dataBefore == null && dataAfter != null; - } - - private static boolean isDelete(final DataObject dataBefore, - final DataObject dataAfter) { - return dataAfter == null && dataBefore != null; - } - - private void writeSubtree(final InstanceIdentifier id, - final DataObject dataAfter, final WriteContext ctx) throws VppException { - LOG.debug("{}: Writing subtree: {}", this, id); - final VppWriter> vppWriter = getNextWriter(id); - - if (vppWriter != null) { - LOG.debug("{}: Writing subtree: {} in: {}", this, id, vppWriter); - vppWriter.update(id, null, dataAfter, ctx); - } else { - // If there's no dedicated writer, use write current - // But we need current data after to do so - final InstanceIdentifier currentId = VppRWUtils.cutId(id, getManagedDataObjectType()); - Optional currentDataAfter = ctx.readAfter(currentId); - LOG.debug("{}: Dedicated subtree writer missing for: {}. Writing current.", this, - VppRWUtils.getNextId(id, getManagedDataObjectType()).getType(), currentDataAfter); - writeCurrent(currentId, castToManaged(currentDataAfter.get()), ctx); - } - } - - private boolean idPointsToCurrent(final @Nonnull InstanceIdentifier id) { - return id.getTargetType().equals(getManagedDataObjectType().getTargetType()); - } - - @SuppressWarnings("unchecked") - private void deleteSubtree(final InstanceIdentifier id, - final DataObject dataBefore, final WriteContext ctx) throws VppException { - LOG.debug("{}: Deleting subtree: {}", this, id); - final VppWriter> vppWriter = getNextWriter(id); - - if (vppWriter != null) { - LOG.debug("{}: Deleting subtree: {} in: {}", this, id, vppWriter); - vppWriter.update(id, dataBefore, null, ctx); - } else { - updateSubtreeFromCurrent(id, ctx); - } - } - - @SuppressWarnings("unchecked") - private void updateSubtreeFromCurrent(final InstanceIdentifier id, final WriteContext ctx) { - final InstanceIdentifier currentId = VppRWUtils.cutId(id, getManagedDataObjectType()); - Optional currentDataBefore = ctx.readBefore(currentId); - Optional currentDataAfter = ctx.readAfter(currentId); - LOG.debug("{}: Dedicated subtree writer missing for: {}. Updating current without subtree", this, - VppRWUtils.getNextId(id, getManagedDataObjectType()).getType(), currentDataAfter); - updateCurrent((InstanceIdentifier) id, castToManaged(currentDataBefore.orNull()), - castToManaged(currentDataAfter.orNull()), ctx); - } - - @SuppressWarnings("unchecked") - private void updateSubtree(final InstanceIdentifier id, - final DataObject dataBefore, - final DataObject dataAfter, - final WriteContext ctx) throws VppException { - LOG.debug("{}: Updating subtree: {}", this, id); - final VppWriter> vppWriter = getNextWriter(id); - - if (vppWriter != null) { - LOG.debug("{}: Updating subtree: {} in: {}", this, id, vppWriter); - vppWriter.update(id, dataBefore, dataAfter, ctx); - } else { - updateSubtreeFromCurrent(id, ctx); - } - } - - private VppWriter> getNextWriter(final InstanceIdentifier id) { - final Class next = VppRWUtils.getNextId(id, getManagedDataObjectType()).getType(); - return childWriters.get(next); - } - - private static List reverseCollection(final Collection original) { - // TODO find a better reverse mechanism (probably a different collection for child writers is necessary) - final ArrayList list = Lists.newArrayList(original); - Collections.reverse(list); - return list; - } - - protected abstract void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final D data, - @Nonnull final WriteContext ctx); - - protected abstract void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final D dataBefore, - @Nonnull final WriteContext ctx); - - protected abstract void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final D dataBefore, - @Nonnull final D dataAfter, - @Nonnull final WriteContext ctx); - - @Nonnull - @Override - public InstanceIdentifier getManagedDataObjectType() { - return instanceIdentifier; - } - - - @Override - public String toString() { - return String.format("Writer[%s]", getManagedDataObjectType().getTargetType().getSimpleName()); - } -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/impl/CompositeChildVppWriter.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/impl/CompositeChildVppWriter.java deleted file mode 100644 index d94e4fedf..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/impl/CompositeChildVppWriter.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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.impl.trans.w.impl; - -import com.google.common.base.Optional; -import io.fd.honeycomb.v3po.impl.trans.util.VppRWUtils; -import io.fd.honeycomb.v3po.impl.trans.w.ChildVppWriter; -import io.fd.honeycomb.v3po.impl.trans.w.WriteContext; -import io.fd.honeycomb.v3po.impl.trans.w.impl.spi.ChildVppWriterCustomizer; -import java.util.List; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.Augmentation; -import org.opendaylight.yangtools.yang.binding.ChildOf; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -public class CompositeChildVppWriter extends AbstractCompositeVppWriter - implements ChildVppWriter { - - private final ChildVppWriterCustomizer customizer; - - public CompositeChildVppWriter(@Nonnull final Class type, - @Nonnull final List>> childWriters, - @Nonnull final List>> augWriters, - @Nonnull final ChildVppWriterCustomizer customizer) { - super(type, childWriters, augWriters); - this.customizer = customizer; - } - - public CompositeChildVppWriter(@Nonnull final Class type, - @Nonnull final List>> childWriters, - @Nonnull final ChildVppWriterCustomizer customizer) { - this(type, childWriters, VppRWUtils.emptyAugWriterList(), customizer); - } - - public CompositeChildVppWriter(@Nonnull final Class type, - @Nonnull final ChildVppWriterCustomizer customizer) { - this(type, VppRWUtils.emptyChildWriterList(), VppRWUtils.emptyAugWriterList(), customizer); - } - - @Override - protected void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D data, - @Nonnull final WriteContext ctx) { - customizer.writeCurrentAttributes(id, data, ctx.getContext()); - } - - @Override - protected void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D dataBefore, - @Nonnull WriteContext ctx) { - customizer.deleteCurrentAttributes(id, dataBefore, ctx.getContext()); - } - - @Override - protected void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D dataBefore, - @Nonnull final D dataAfter, @Nonnull WriteContext ctx) { - customizer.updateCurrentAttributes(id, dataBefore, dataAfter, ctx.getContext()); - } - - @Override - public void writeChild(@Nonnull final InstanceIdentifier parentId, - @Nonnull final DataObject parentData, @Nonnull WriteContext ctx) { - final InstanceIdentifier currentId = VppRWUtils.appendTypeToId(parentId, getManagedDataObjectType()); - final Optional currentData = customizer.extract(currentId, parentData); - if(currentData.isPresent()) { - writeCurrent(currentId, currentData.get(), ctx); - } - } - - @Override - public void deleteChild(@Nonnull final InstanceIdentifier parentId, - @Nonnull final DataObject parentData, - @Nonnull final WriteContext ctx) { - final InstanceIdentifier currentId = VppRWUtils.appendTypeToId(parentId, getManagedDataObjectType()); - final Optional currentData = customizer.extract(currentId, parentData); - if(currentData.isPresent()) { - deleteCurrent(currentId, currentData.get(), ctx); - } - } - - @Override - public void updateChild(@Nonnull final InstanceIdentifier parentId, - @Nonnull final DataObject parentDataBefore, @Nonnull final DataObject parentDataAfter, - @Nonnull final WriteContext ctx) { - final InstanceIdentifier currentId = VppRWUtils.appendTypeToId(parentId, getManagedDataObjectType()); - final Optional before = customizer.extract(currentId, parentDataBefore); - final Optional after = customizer.extract(currentId, parentDataAfter); - if(before.isPresent() && after.isPresent()) { - updateCurrent(currentId, before.get(), after.get(), ctx); - } - } -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/impl/CompositeListVppWriter.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/impl/CompositeListVppWriter.java deleted file mode 100644 index 1722b4652..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/impl/CompositeListVppWriter.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * 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.impl.trans.w.impl; - -import com.google.common.base.Function; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import io.fd.honeycomb.v3po.impl.trans.util.VppRWUtils; -import io.fd.honeycomb.v3po.impl.trans.w.ChildVppWriter; -import io.fd.honeycomb.v3po.impl.trans.w.WriteContext; -import io.fd.honeycomb.v3po.impl.trans.w.impl.spi.ListVppWriterCustomizer; -import java.util.List; -import java.util.Map; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.Augmentation; -import org.opendaylight.yangtools.yang.binding.ChildOf; -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; - -public class CompositeListVppWriter, K extends Identifier> extends AbstractCompositeVppWriter - implements ChildVppWriter { - - public static final Function INDEX_FUNCTION = new Function() { - @Override - public Object apply(final DataObject input) { - return input instanceof Identifiable - ? ((Identifiable) input).getKey() - : input; - } - }; - - - private final ListVppWriterCustomizer customizer; - - public CompositeListVppWriter(@Nonnull final Class type, - @Nonnull final List>> childWriters, - @Nonnull final List>> augWriters, - @Nonnull final ListVppWriterCustomizer customizer) { - super(type, childWriters, augWriters); - this.customizer = customizer; - } - - public CompositeListVppWriter(@Nonnull final Class type, - @Nonnull final List>> childWriters, - @Nonnull final ListVppWriterCustomizer customizer) { - this(type, childWriters, VppRWUtils.emptyAugWriterList(), customizer); - } - - public CompositeListVppWriter(@Nonnull final Class type, - @Nonnull final ListVppWriterCustomizer customizer) { - this(type, VppRWUtils.emptyChildWriterList(), VppRWUtils.emptyAugWriterList(), customizer); - - } - - @Override - protected void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D data, - @Nonnull final WriteContext ctx) { - customizer.writeCurrentAttributes(id, data, ctx.getContext()); - } - - @Override - protected void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D dataBefore, - @Nonnull final WriteContext ctx) { - customizer.deleteCurrentAttributes(id, dataBefore, ctx.getContext()); - } - - @Override - protected void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D dataBefore, - @Nonnull final D dataAfter, @Nonnull final WriteContext ctx) { - customizer.updateCurrentAttributes(id, dataBefore, dataAfter, ctx.getContext()); - } - - @Override - public void writeChild(@Nonnull final InstanceIdentifier parentId, - @Nonnull final DataObject parentData, - @Nonnull final WriteContext ctx) { - final InstanceIdentifier currentId = VppRWUtils.appendTypeToId(parentId, getManagedDataObjectType()); - final List currentData = customizer.extract(currentId, parentData); - for (D entry : currentData) { - writeCurrent(currentId, entry, ctx); - } - } - - @Override - public void deleteChild(@Nonnull final InstanceIdentifier parentId, - @Nonnull final DataObject parentDataBefore, - @Nonnull final WriteContext ctx) { - final InstanceIdentifier currentId = VppRWUtils.appendTypeToId(parentId, getManagedDataObjectType()); - final List dataBefore = customizer.extract(currentId, parentDataBefore); - for (D entry : dataBefore) { - deleteCurrent(currentId, entry, ctx); - } - } - - @Override - public void updateChild(@Nonnull final InstanceIdentifier parentId, - @Nonnull final DataObject parentDataBefore, @Nonnull final DataObject parentDataAfter, - @Nonnull final WriteContext ctx) { - final InstanceIdentifier currentId = VppRWUtils.appendTypeToId(parentId, getManagedDataObjectType()); - final ImmutableMap - dataBefore = Maps.uniqueIndex(customizer.extract(currentId, parentDataBefore), INDEX_FUNCTION); - final ImmutableMap - dataAfter = Maps.uniqueIndex(customizer.extract(currentId, parentDataAfter), INDEX_FUNCTION); - - for (Map.Entry after : dataAfter.entrySet()) { - final D before = dataBefore.get(after.getKey()); - if(before == null) { - writeCurrent(currentId, after.getValue(), ctx); - } else { - updateCurrent(currentId, before, after.getValue(), ctx); - } - } - - // Delete the rest in dataBefore - for (Object deletedNodeKey : Sets.difference(dataBefore.keySet(), dataAfter.keySet())) { - final D deleted = dataBefore.get(deletedNodeKey); - deleteCurrent(currentId, deleted, ctx); - } - - } - - @Override - protected void writeCurrent(final InstanceIdentifier id, final D data, final WriteContext ctx) { - // Make sure the key is present - if(isWildcarded(id)) { - super.writeCurrent(getSpecificId(id, data), data, ctx); - } else { - super.writeCurrent(id, data, ctx); - } - } - - @Override - protected void updateCurrent(final InstanceIdentifier id, final D dataBefore, final D dataAfter, - final WriteContext ctx) { - // Make sure the key is present - if(isWildcarded(id)) { - super.updateCurrent(getSpecificId(id, dataBefore), dataBefore, dataAfter, ctx); - } else { - super.updateCurrent(id, dataBefore, dataAfter, ctx); - } - } - - @Override - protected void deleteCurrent(final InstanceIdentifier id, final D dataBefore, final WriteContext ctx) { - // Make sure the key is present - if(isWildcarded(id)) { - super.deleteCurrent(getSpecificId(id, dataBefore), dataBefore, ctx); - } else { - super.deleteCurrent(id, dataBefore, ctx); - } - } - - private boolean isWildcarded(final InstanceIdentifier id) { - return id.firstIdentifierOf(getManagedDataObjectType().getTargetType()).isWildcarded(); - } - - private InstanceIdentifier getSpecificId(final InstanceIdentifier currentId, final D current) { - return VppRWUtils.replaceLastInId(currentId, - new InstanceIdentifier.IdentifiableItem<>(currentId.getTargetType(), current.getKey())); - } -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/impl/CompositeRootVppWriter.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/impl/CompositeRootVppWriter.java deleted file mode 100644 index a7139e57a..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/impl/CompositeRootVppWriter.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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.impl.trans.w.impl; - -import io.fd.honeycomb.v3po.impl.trans.util.VppRWUtils; -import io.fd.honeycomb.v3po.impl.trans.w.ChildVppWriter; -import io.fd.honeycomb.v3po.impl.trans.w.WriteContext; -import io.fd.honeycomb.v3po.impl.trans.w.impl.spi.RootVppWriterCustomizer; -import java.util.List; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.Augmentation; -import org.opendaylight.yangtools.yang.binding.ChildOf; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -public class CompositeRootVppWriter extends AbstractCompositeVppWriter { - - private final RootVppWriterCustomizer customizer; - - public CompositeRootVppWriter(@Nonnull final Class type, - @Nonnull final List>> childWriters, - @Nonnull final List>> augWriters, - @Nonnull final RootVppWriterCustomizer customizer) { - super(type, childWriters, augWriters); - this.customizer = customizer; - } - - public CompositeRootVppWriter(@Nonnull final Class type, - @Nonnull final List>> childWriters, - @Nonnull final RootVppWriterCustomizer customizer) { - this(type, childWriters, VppRWUtils.emptyAugWriterList(), customizer); - } - - public CompositeRootVppWriter(@Nonnull final Class type, - @Nonnull final RootVppWriterCustomizer customizer) { - this(type, VppRWUtils.emptyChildWriterList(), VppRWUtils.emptyAugWriterList(), customizer); - } - - @Override - protected void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D data, - @Nonnull final WriteContext ctx) { - customizer.writeCurrentAttributes(id, data, ctx.getContext()); - } - - @Override - protected void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D dataBefore, - @Nonnull final WriteContext ctx) { - customizer.deleteCurrentAttributes(id, dataBefore, ctx.getContext()); - } - - @Override - protected void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final D dataBefore, - @Nonnull final D dataAfter, - @Nonnull final WriteContext ctx) { - customizer.updateCurrentAttributes(id, dataBefore, dataAfter, ctx.getContext()); - } -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/impl/spi/ChildVppWriterCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/impl/spi/ChildVppWriterCustomizer.java deleted file mode 100644 index 1e79c6830..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/impl/spi/ChildVppWriterCustomizer.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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.impl.trans.w.impl.spi; - -import com.google.common.annotations.Beta; -import com.google.common.base.Optional; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * {@link io.fd.honeycomb.v3po.impl.trans.w.impl.CompositeChildVppWriter} SPI to customize its behavior - * - * @param Specific DataObject derived type (Identifiable), that is handled by this customizer - */ -@Beta -public interface ChildVppWriterCustomizer extends RootVppWriterCustomizer { - - /** - * Get child of parentData identified by currentId - * - * @param currentId Identifier(from root) of data being extracted - * @param parentData Parent data object from which managed data object must be extracted - */ - @Nonnull - Optional extract(@Nonnull final InstanceIdentifier currentId, @Nonnull final DataObject parentData); - -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/impl/spi/ListVppWriterCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/impl/spi/ListVppWriterCustomizer.java deleted file mode 100644 index 6e72fc719..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/impl/spi/ListVppWriterCustomizer.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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.impl.trans.w.impl.spi; - -import com.google.common.annotations.Beta; -import java.util.List; -import javax.annotation.Nonnull; -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; - -/** - * {@link io.fd.honeycomb.v3po.impl.trans.w.impl.CompositeListVppWriter} SPI to customize its behavior - * - * @param Specific DataObject derived type (Identifiable), that is handled by this customizer - * @param Specific Identifier for handled type (C) - */ -@Beta -public interface ListVppWriterCustomizer, K extends Identifier> extends RootVppWriterCustomizer { - - /** - * Get children of parentData identified by currentId - * - * @param currentId Identifier(from root) of data being extracted - * @param parentData Parent data object from which managed data object must be extracted - */ - @Nonnull - List extract(@Nonnull final InstanceIdentifier currentId, @Nonnull final DataObject parentData); - -} \ No newline at end of file diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/impl/spi/RootVppWriterCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/impl/spi/RootVppWriterCustomizer.java deleted file mode 100644 index 0fa89d2af..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/impl/spi/RootVppWriterCustomizer.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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.impl.trans.w.impl.spi; - -import com.google.common.annotations.Beta; -import io.fd.honeycomb.v3po.impl.trans.util.Context; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * {@link io.fd.honeycomb.v3po.impl.trans.w.impl.CompositeRootVppWriter} SPI to customize its behavior - * - * @param Specific DataObject derived type, that is handled by this customizer - */ -@Beta -public interface RootVppWriterCustomizer { - - /** - * Handle write operation. C from CRUD. - * - * @param id Identifier(from root) of data being written - * @param dataAfter New data to be written - * @param writeContext Write context can be used to store any useful information and then utilized by other customizers - */ - void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final D dataAfter, - @Nonnull final Context writeContext); - - /** - * Handle update operation. U from CRUD. - * - * @param id Identifier(from root) of data being written - * @param dataBefore Old data - * @param dataAfter New, updated data - * @param writeContext Write context can be used to store any useful information and then utilized by other customizers - */ - void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final D dataBefore, - @Nonnull final D dataAfter, - @Nonnull final Context writeContext); - - /** - * Handle delete operation. D from CRUD. - * - * @param id Identifier(from root) of data being written - * @param dataBefore Old data being deleted - * @param writeContext Write context can be used to store any useful information and then utilized by other customizers - */ - void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final D dataBefore, - @Nonnull final Context writeContext); -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/util/DelegatingWriterRegistry.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/util/DelegatingWriterRegistry.java deleted file mode 100644 index cc1188e17..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/util/DelegatingWriterRegistry.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * 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.impl.trans.w.util; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.base.Function; -import com.google.common.collect.Collections2; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; -import io.fd.honeycomb.v3po.impl.trans.VppException; -import io.fd.honeycomb.v3po.impl.trans.util.VppRWUtils; -import io.fd.honeycomb.v3po.impl.trans.w.VppWriter; -import io.fd.honeycomb.v3po.impl.trans.w.WriteContext; -import io.fd.honeycomb.v3po.impl.trans.w.WriterRegistry; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Simple writer registry able to perform and aggregated read (ROOT write) on top of all provided writers. Also able to - * delegate a specific read to one of the delegate writers. - * - * This could serve as a utility to hold & hide all available writers in upper layers. - */ -public final class DelegatingWriterRegistry implements WriterRegistry { - - private static final Logger LOG = LoggerFactory.getLogger(DelegatingWriterRegistry.class); - - private static final Function, Class> ID_TO_CLASS = - new Function, Class>() { - @Override - public Class apply(final InstanceIdentifier input) { - return input.getTargetType(); - } - }; - - private final Map, VppWriter> rootWriters; - - /** - * Create new {@link DelegatingWriterRegistry} - * - * @param rootWriters List of delegate writers - */ - public DelegatingWriterRegistry(@Nonnull final List> rootWriters) { - this.rootWriters = VppRWUtils.uniqueLinkedIndex(checkNotNull(rootWriters), VppRWUtils.MANAGER_CLASS_FUNCTION); - } - - /** - * @throws UnsupportedOperationException This getter is not supported for writer registry since it does not manage a - * specific node type - */ - @Nonnull - @Override - public InstanceIdentifier getManagedDataObjectType() { - throw new UnsupportedOperationException("Root registry has no type"); - } - - @Override - public void update(@Nonnull final InstanceIdentifier id, - @Nullable final DataObject dataBefore, - @Nullable final DataObject dataAfter, - @Nonnull final WriteContext ctx) throws VppException { - final InstanceIdentifier.PathArgument first = checkNotNull( - Iterables.getFirst(id.getPathArguments(), null), "Empty id"); - final VppWriter vppWriter = rootWriters.get(first.getType()); - checkNotNull(vppWriter, - "Unable to write %s. Missing writer. Current writers for: %s", id, rootWriters.keySet()); - vppWriter.update(id, dataBefore, dataAfter, ctx); - } - - @Override - public void update(@Nonnull final Map, DataObject> nodesBefore, - @Nonnull final Map, DataObject> nodesAfter, - @Nonnull final WriteContext ctx) throws VppException { - checkAllWritersPresent(nodesBefore); - checkAllWritersPresent(nodesAfter); - - final List> processedNodes = Lists.newArrayList(); - - for (Map.Entry, VppWriter> rootWriterEntry : rootWriters - .entrySet()) { - - final InstanceIdentifier id = rootWriterEntry.getValue().getManagedDataObjectType(); - - final DataObject dataBefore = nodesBefore.get(id); - final DataObject dataAfter = nodesAfter.get(id); - - // No change to current writer - if (dataBefore == null && dataAfter == null) { - continue; - } - - LOG.debug("ChangesProcessor.applyChanges() processing dataBefore={}, dataAfter={}", dataBefore, dataAfter); - - try { - update(id, dataBefore, dataAfter, ctx); - processedNodes.add(id); - } catch (Exception e) { - LOG.error("Error while processing data change of: {} (before={}, after={})", - id, dataBefore, dataAfter, e); - throw new BulkUpdateException( - id, new ReverterImpl(this, processedNodes, nodesBefore, nodesAfter, ctx), e); - } - } - } - - private void checkAllWritersPresent(final @Nonnull Map, DataObject> nodesBefore) { - checkArgument(rootWriters.keySet().containsAll(Collections2.transform(nodesBefore.keySet(), ID_TO_CLASS)), - "Unable to handle all changes. Missing dedicated writers for: %s", - Sets.difference(nodesBefore.keySet(), rootWriters.keySet())); - } - - private static final class ReverterImpl implements Reverter { - private final WriterRegistry delegatingWriterRegistry; - private final List> processedNodes; - private final Map, DataObject> nodesBefore; - private final Map, DataObject> nodesAfter; - private final WriteContext ctx; - - ReverterImpl(final WriterRegistry delegatingWriterRegistry, - final List> processedNodes, - final Map, DataObject> nodesBefore, - final Map, DataObject> nodesAfter, final WriteContext ctx) { - this.delegatingWriterRegistry = delegatingWriterRegistry; - this.processedNodes = processedNodes; - this.nodesBefore = nodesBefore; - this.nodesAfter = nodesAfter; - this.ctx = ctx; - } - - @Override - public void revert() throws RevertFailedException { - final LinkedList> notReverted = new LinkedList<>(processedNodes); - - while (notReverted.size() > 0) { - final InstanceIdentifier node = notReverted.peekLast(); - LOG.debug("ChangesProcessor.revertChanges() processing node={}", node); - - final DataObject dataBefore = nodesBefore.get(node); - final DataObject dataAfter = nodesAfter.get(node); - - // revert a change by invoking writer with reordered arguments - try { - delegatingWriterRegistry.update(node, dataAfter, dataBefore, ctx); - notReverted.removeLast(); // change was successfully reverted - } catch (Exception e) { - throw new RevertFailedException(notReverted, e); - } - - } - } - } -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/util/NoopWriterCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/util/NoopWriterCustomizer.java deleted file mode 100644 index 7691f558b..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/util/NoopWriterCustomizer.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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.impl.trans.w.util; - -import io.fd.honeycomb.v3po.impl.trans.util.Context; -import io.fd.honeycomb.v3po.impl.trans.w.impl.spi.RootVppWriterCustomizer; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Customizer not performing any changes on current level. Suitable for nodes that don't have any leaves and all of - * its child nodes are managed by dedicated writers - */ -public class NoopWriterCustomizer implements RootVppWriterCustomizer { - - @Override - public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D dataAfter, - @Nonnull final Context ctx) { - - } - - @Override - public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D dataBefore, - @Nonnull final D dataAfter, - @Nonnull final Context ctx) { - - } - - @Override - public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D dataBefore, - @Nonnull final Context ctx) { - - } -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/util/ReflexiveChildWriterCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/util/ReflexiveChildWriterCustomizer.java deleted file mode 100644 index 9d324a059..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/util/ReflexiveChildWriterCustomizer.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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.impl.trans.w.util; - -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -import com.google.common.collect.Iterables; -import io.fd.honeycomb.v3po.impl.trans.util.ReflectionUtils; -import io.fd.honeycomb.v3po.impl.trans.w.impl.spi.ChildVppWriterCustomizer; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Collections; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Might be slow ! - */ -public class ReflexiveChildWriterCustomizer extends NoopWriterCustomizer implements - ChildVppWriterCustomizer { - - @Nonnull - @Override - @SuppressWarnings("unchecked") - public Optional extract(@Nonnull final InstanceIdentifier currentId, @Nonnull final DataObject parentData) { - final Class currentType = currentId.getTargetType(); - final Optional method = ReflectionUtils.findMethodReflex(getParentType(currentId), - "get" + currentType.getSimpleName(), Collections.>emptyList(), currentType); - - Preconditions.checkArgument(method.isPresent(), "Unable to get %s from %s", currentType, parentData); - - try { - return method.isPresent() - ? Optional.of((C) method.get().invoke(parentData)) - : Optional.absent(); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new IllegalArgumentException("Unable to get " + currentType + " from " + parentData, e); - } - } - - private Class getParentType(final @Nonnull InstanceIdentifier currentId) { - return Iterables.get(currentId.getPathArguments(), Iterables.size(currentId.getPathArguments()) - 2).getType(); - } -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/util/TransactionWriteContext.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/util/TransactionWriteContext.java deleted file mode 100644 index 21e5f19ce..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/util/TransactionWriteContext.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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.impl.trans.w.util; - -import com.google.common.base.Optional; -import com.google.common.util.concurrent.CheckedFuture; -import io.fd.honeycomb.v3po.impl.trans.util.Context; -import io.fd.honeycomb.v3po.impl.trans.w.WriteContext; -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.ReadFailedException; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; -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.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; - -/** - * Transaction based WriteContext - */ -public final class TransactionWriteContext implements WriteContext { - - private final DOMDataReadOnlyTransaction beforeTx; - private final DOMDataReadOnlyTransaction afterTx; - private final Context ctx; - private final BindingNormalizedNodeSerializer serializer; - - public TransactionWriteContext(final BindingNormalizedNodeSerializer serializer, - final DOMDataReadOnlyTransaction beforeTx, - final DOMDataReadOnlyTransaction afterTx) { - this.serializer = serializer; - this.beforeTx = beforeTx; - this.afterTx = afterTx; - this.ctx = new Context(); - } - - // TODO make this asynchronous - - @Override - public Optional readBefore(@Nonnull final InstanceIdentifier currentId) { - return read(currentId, beforeTx); - } - - private Optional read(final InstanceIdentifier currentId, - final DOMDataReadOnlyTransaction tx) { - final YangInstanceIdentifier path = serializer.toYangInstanceIdentifier(currentId); - - final CheckedFuture>, ReadFailedException> read = - tx.read(LogicalDatastoreType.CONFIGURATION, path); - - try { - // TODO once the APIs are asynchronous use just Futures.transform - final Optional> optional = read.checkedGet(); - - if (!optional.isPresent()) { - return Optional.absent(); - } - - final NormalizedNode data = optional.get(); - final Map.Entry, DataObject> entry = serializer.fromNormalizedNode(path, data); - - return Optional.of(entry.getValue()); - } catch (ReadFailedException e) { - throw new IllegalStateException("Unable to perform read", e); - } - } - - @Override - public Optional readAfter(@Nonnull final InstanceIdentifier currentId) { - return read(currentId, afterTx); - } - - @Override - public Context getContext() { - return ctx; - } - - /** - * Does not close the transactions - */ - @Override - public void close() { - ctx.close(); - } -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainCustomizer.java deleted file mode 100644 index c56ebb1a8..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainCustomizer.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * 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.impl.vpp; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; - -import io.fd.honeycomb.v3po.impl.trans.util.Context; -import io.fd.honeycomb.v3po.impl.trans.util.VppApiCustomizer; -import io.fd.honeycomb.v3po.impl.trans.w.impl.spi.ListVppWriterCustomizer; -import java.util.List; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class BridgeDomainCustomizer - extends VppApiCustomizer - implements ListVppWriterCustomizer { - - private static final Logger LOG = LoggerFactory.getLogger(BridgeDomainCustomizer.class); - - private static final byte ADD_OR_UPDATE_BD = (byte) 1; - private static final int RESPONSE_NOT_READY = -77; - private static final int RELEASE = 1; - - public BridgeDomainCustomizer(final org.openvpp.vppjapi.vppApi api) { - super(api); - } - - @Nonnull - @Override - public List extract(@Nonnull final InstanceIdentifier currentId, - @Nonnull final DataObject parentData) { - return ((BridgeDomains) parentData).getBridgeDomain(); - } - - private int waitForResponse(final int ctxId) { - int rv; - while ((rv = getVppApi().getRetval(ctxId, RELEASE)) == RESPONSE_NOT_READY) { - // TODO limit attempts - } - return rv; - } - - private int addOrUpdateBridgeDomain(final int bdId, @Nonnull final BridgeDomain bd) { - byte flood = booleanToByte(bd.isFlood()); - byte forward = booleanToByte(bd.isForward()); - byte learn = booleanToByte(bd.isLearn()); - byte uuf = booleanToByte(bd.isUnknownUnicastFlood()); - byte arpTerm = booleanToByte(bd.isArpTermination()); - - int ctxId = getVppApi().bridgeDomainAddDel(bdId, flood, forward, learn, uuf, arpTerm, ADD_OR_UPDATE_BD); - return waitForResponse(ctxId); - } - - @Override - public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final BridgeDomain current, - @Nonnull final Context ctx) { - LOG.debug("writeCurrentAttributes: id={}, current={}, ctx={}", id, current, ctx); - final String bdName = current.getName(); - int bdId = getVppApi().findOrAddBridgeDomainId(bdName); - checkState(bdId > 0, "Unable to find or create bridge domain. Return code: %s", bdId); - - int rv = addOrUpdateBridgeDomain(bdId, current); - - checkState(rv >= 0, "Bridge domain %s(%s) write failed. Return code: %s", bdName, bdId, rv); - LOG.debug("Bridge domain {} written as {} successfully", bdName, bdId); - } - - private byte booleanToByte(@Nullable final Boolean aBoolean) { - return aBoolean != null && aBoolean ? (byte) 1 : (byte) 0; - } - - @Override - public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final BridgeDomain dataBefore, - @Nonnull final Context ctx) { - LOG.debug("deleteCurrentAttributes: id={}, dataBefore={}, ctx={}", id, dataBefore, ctx); - String bdName = id.firstKeyOf(BridgeDomain.class).getName(); - - int bdId = getVppApi().bridgeDomainIdFromName(bdName); - checkState(bdId > 0, "Unable to delete bridge domain. Does not exist. Return code: %s", bdId); - - int ctxId = getVppApi().bridgeDomainAddDel(bdId, - (byte) 0 /* flood */, - (byte) 0 /* forward */, - (byte) 0 /* learn */, - (byte) 0 /* uuf */, - (byte) 0 /* arpTerm */, - (byte) 0 /* isAdd */); - - int rv = waitForResponse(ctxId); - - checkState(rv >= 0, "Bridge domain delete failed. Return code: %s", rv); - LOG.debug("Bridge domain {} deleted as {} successfully", bdName, bdId); - } - - @Override - public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final BridgeDomain dataBefore, @Nonnull final BridgeDomain dataAfter, - @Nonnull final Context ctx) { - LOG.debug("updateCurrentAttributes: id={}, dataBefore={}, dataAfter={}, ctx={}", id, dataBefore, dataAfter, ctx); - - final String bdName = checkNotNull(dataAfter.getName()); - checkArgument(bdName.equals(dataBefore.getName()), "BridgeDomain name changed. It should be deleted and then created."); - - int bdId = getVppApi().bridgeDomainIdFromName(bdName); - checkState(bdId > 0, "Unable to find bridge domain. Return code: %s", bdId); - - final int rv = addOrUpdateBridgeDomain(bdId, dataAfter); - - checkState(rv >= 0, "Bridge domain %s(%s) update failed. Return code: %s", bdName, bdId, rv); - LOG.debug("Bridge domain {}({}) updated successfully", bdName, bdId); - } - -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vppstate/BridgeDomainCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vppstate/BridgeDomainCustomizer.java deleted file mode 100644 index 08daa4e40..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vppstate/BridgeDomainCustomizer.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * 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.impl.vppstate; - -import com.google.common.collect.Lists; -import io.fd.honeycomb.v3po.impl.trans.r.impl.spi.ListVppReaderCustomizer; -import io.fd.honeycomb.v3po.impl.trans.util.Context; -import io.fd.honeycomb.v3po.impl.trans.util.VppApiCustomizer; -import java.util.ArrayList; -import java.util.List; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomainsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.Interface; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.InterfaceBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.InterfaceKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.L2Fib; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.L2FibBuilder; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.vppjapi.vppBridgeDomainDetails; -import org.openvpp.vppjapi.vppBridgeDomainInterfaceDetails; -import org.openvpp.vppjapi.vppL2Fib; - -public final class BridgeDomainCustomizer extends VppApiCustomizer - implements ListVppReaderCustomizer { - - public BridgeDomainCustomizer(@Nonnull final org.openvpp.vppjapi.vppApi vppApi) { - super(vppApi); - } - - @Override - public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, - @Nonnull final BridgeDomainBuilder builder, @Nonnull final Context context) { - final BridgeDomainKey key = id.firstKeyOf(id.getTargetType()); - // TODO find out if bd exists based on name and if not return - - final int bdId = getVppApi().bridgeDomainIdFromName(key.getName()); - final vppBridgeDomainDetails bridgeDomainDetails = getVppApi().getBridgeDomainDetails(bdId); - - builder.setName(key.getName()); - // builder.setName(bridgeDomainDetails.name); - builder.setArpTermination(bridgeDomainDetails.arpTerm); - builder.setFlood(bridgeDomainDetails.flood); - builder.setForward(bridgeDomainDetails.forward); - builder.setLearn(bridgeDomainDetails.learn); - builder.setUnknownUnicastFlood(bridgeDomainDetails.uuFlood); - - builder.setInterface(getIfcs(bridgeDomainDetails)); - - final vppL2Fib[] vppL2Fibs = getVppApi().l2FibTableDump(bdId); - - final List l2Fibs = Lists.newArrayListWithCapacity(vppL2Fibs.length); - for (vppL2Fib vppL2Fib : vppL2Fibs) { - l2Fibs.add(new L2FibBuilder() - .setAction((vppL2Fib.filter - ? L2Fib.Action.Filter - : L2Fib.Action.Forward)) - .setBridgedVirtualInterface(vppL2Fib.bridgedVirtualInterface) - .setOutgoingInterface(vppL2Fib.outgoingInterface) - .setPhysAddress(new PhysAddress(getMacAddress(vppL2Fib.physAddress))) - .setStaticConfig(vppL2Fib.staticConfig) - .build()); - } - builder.setL2Fib(l2Fibs); - } - - private static String getMacAddress(byte[] mac) { - StringBuilder sb = new StringBuilder(18); - for (byte b : mac) { - if (sb.length() > 0) { - sb.append(':'); - } - sb.append(String.format("%02x", b)); - } - return sb.toString(); - } - - private List getIfcs(final vppBridgeDomainDetails bridgeDomainDetails) { - final List ifcs = new ArrayList<>(bridgeDomainDetails.interfaces.length); - for (vppBridgeDomainInterfaceDetails anInterface : bridgeDomainDetails.interfaces) { - ifcs.add(new InterfaceBuilder() - .setBridgedVirtualInterface(bridgeDomainDetails.bviInterfaceName.equals(anInterface.interfaceName)) - .setName(anInterface.interfaceName) - .setKey(new InterfaceKey(anInterface.interfaceName)) - .build()); - } - return ifcs; - } - - @Nonnull - @Override - public BridgeDomainBuilder getBuilder(@Nonnull final InstanceIdentifier id) { - return new BridgeDomainBuilder(); - } - - @Nonnull - @Override - public List getAllIds(@Nonnull final InstanceIdentifier id, @Nonnull final Context context) { - final int[] bIds = getVppApi().bridgeDomainDump(-1); - final List allIds = new ArrayList<>(bIds.length); - for (int bId : bIds) { - // FIXME this is highly inefficient having to dump all of the bridge domain details - // Use context to store already read information - // TODO Or just remove the getAllIds method and replace with a simple readAll - final vppBridgeDomainDetails bridgeDomainDetails = getVppApi().getBridgeDomainDetails(bId); - final String bName = bridgeDomainDetails.name; - allIds.add(new BridgeDomainKey(bName)); - } - - return allIds; - } - - @Override - public void merge(@Nonnull final Builder builder, @Nonnull final List readData) { - ((BridgeDomainsBuilder) builder).setBridgeDomain(readData); - } -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vppstate/VersionCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vppstate/VersionCustomizer.java deleted file mode 100644 index 4cdacaa1b..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vppstate/VersionCustomizer.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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.impl.vppstate; - -import io.fd.honeycomb.v3po.impl.trans.r.impl.spi.ChildVppReaderCustomizer; -import io.fd.honeycomb.v3po.impl.trans.util.Context; -import io.fd.honeycomb.v3po.impl.trans.util.VppApiCustomizer; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppStateBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.Version; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.VersionBuilder; -import org.opendaylight.yangtools.concepts.Builder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.vppjapi.vppVersion; - -public final class VersionCustomizer - extends VppApiCustomizer - implements ChildVppReaderCustomizer { - - public VersionCustomizer(@Nonnull final org.openvpp.vppjapi.vppApi vppApi) { - super(vppApi); - } - - @Override - public void merge(@Nonnull final Builder parentBuilder, @Nonnull final Version readValue) { - ((VppStateBuilder) parentBuilder).setVersion(readValue); - } - - @Nonnull - @Override - public VersionBuilder getBuilder(@Nonnull InstanceIdentifier id) { - return new VersionBuilder(); - } - - @Override - public void readCurrentAttributes(@Nonnull InstanceIdentifier id, @Nonnull final VersionBuilder builder, - @Nonnull final Context context) { - final vppVersion vppVersion = getVppApi().getVppVersion(); - builder.setBranch(vppVersion.gitBranch); - builder.setName(vppVersion.programName); - builder.setBuildDate(vppVersion.buildDate); - builder.setBuildDirectory(vppVersion.buildDirectory); - } -} diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VPPConfigDataTreeTest.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VPPConfigDataTreeTest.java index 8719a5356..207a64a99 100644 --- a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VPPConfigDataTreeTest.java +++ b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VPPConfigDataTreeTest.java @@ -31,9 +31,9 @@ import static org.mockito.MockitoAnnotations.initMocks; import com.google.common.base.Optional; import com.google.common.util.concurrent.CheckedFuture; -import io.fd.honeycomb.v3po.impl.trans.VppException; -import io.fd.honeycomb.v3po.impl.trans.w.WriteContext; -import io.fd.honeycomb.v3po.impl.trans.w.WriterRegistry; +import io.fd.honeycomb.v3po.vpp.facade.VppException; +import io.fd.honeycomb.v3po.vpp.facade.write.WriteContext; +import io.fd.honeycomb.v3po.vpp.facade.write.WriterRegistry; import java.util.ArrayList; import java.util.Collections; import java.util.List; diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerInitializationProviderTest.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerInitializationProviderTest.java index 30cebf2f9..2c50ec92d 100644 --- a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerInitializationProviderTest.java +++ b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerInitializationProviderTest.java @@ -26,7 +26,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.MockitoAnnotations.initMocks; import com.google.common.util.concurrent.CheckedFuture; -import io.fd.honeycomb.v3po.impl.trans.r.ReaderRegistry; +import io.fd.honeycomb.v3po.vpp.facade.read.ReaderRegistry; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppOperationalDataTreeTest.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppOperationalDataTreeTest.java index 493a01912..09e70941b 100644 --- a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppOperationalDataTreeTest.java +++ b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppOperationalDataTreeTest.java @@ -34,8 +34,8 @@ 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 io.fd.honeycomb.v3po.impl.trans.r.ReadContext; -import io.fd.honeycomb.v3po.impl.trans.r.ReaderRegistry; +import io.fd.honeycomb.v3po.vpp.facade.read.ReadContext; +import io.fd.honeycomb.v3po.vpp.facade.read.ReaderRegistry; import java.util.Map; import org.junit.Before; import org.junit.Test; @@ -121,7 +121,7 @@ public class VppOperationalDataTreeTest { @Test public void testReadFailed() throws Exception{ - doThrow(io.fd.honeycomb.v3po.impl.trans.ReadFailedException.class).when(reader).readAll(any(ReadContext.class)); + doThrow(io.fd.honeycomb.v3po.vpp.facade.read.ReadFailedException.class).when(reader).readAll(any(ReadContext.class)); final CheckedFuture>, ReadFailedException> future = operationalData.read( YangInstanceIdentifier.EMPTY); @@ -129,7 +129,7 @@ public class VppOperationalDataTreeTest { try { future.checkedGet(); } catch (ReadFailedException e) { - assertTrue(e.getCause() instanceof io.fd.honeycomb.v3po.impl.trans.ReadFailedException); + assertTrue(e.getCause() instanceof io.fd.honeycomb.v3po.vpp.facade.read.ReadFailedException); return; } fail("ReadFailedException was expected"); diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/ReadFailedExceptionTest.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/ReadFailedExceptionTest.java deleted file mode 100644 index b815434a8..000000000 --- a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/ReadFailedExceptionTest.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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.impl.trans; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import org.junit.Test; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.Interface; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -public class ReadFailedExceptionTest { - - @Test - public void testInstantiation() { - final InstanceIdentifier id = InstanceIdentifier.create(BridgeDomain.class); - ReadFailedException e = new ReadFailedException(id); - assertEquals(id, e.getFailedId()); - assertNull(e.getCause()); - assertTrue(e.getMessage().contains(id.toString())); - } - - @Test - public void testInstantiationWithCause() { - final InstanceIdentifier id = InstanceIdentifier.create(Interface.class); - final RuntimeException cause = new RuntimeException(); - ReadFailedException e = new ReadFailedException(id, cause); - assertEquals(id, e.getFailedId()); - assertEquals(cause, e.getCause()); - assertTrue(e.getMessage().contains(id.toString())); - } - - @Test(expected = NullPointerException.class) - public void testInstantiationFailed() { - new ReadFailedException(null); - } -} \ No newline at end of file diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/VppApiInvocationExceptionTest.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/VppApiInvocationExceptionTest.java deleted file mode 100644 index fed792a3b..000000000 --- a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/VppApiInvocationExceptionTest.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.impl.trans; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.util.Random; -import org.junit.Test; - -public class VppApiInvocationExceptionTest { - - @Test - public void testInstantiation() { - final String apiMethodName = "methodName"; - final int ctxId = 1; - final int code = -1; - VppApiInvocationException e = new VppApiInvocationException(apiMethodName, ctxId, code); - assertEquals(apiMethodName, e.getMethodName()); - assertEquals(ctxId, e.getCtxId()); - assertEquals(code, e.getErrorCode()); - assertTrue(e.getMessage().contains(apiMethodName)); - assertTrue(e.getMessage().contains(String.valueOf(code))); - assertTrue(e.getMessage().contains(String.valueOf(ctxId))); - } - - @Test(expected = IllegalArgumentException.class) - public void testInstantiationFailed() { - final int code = new Random().nextInt(Integer.MAX_VALUE); - VppApiInvocationException e = new VppApiInvocationException("apiMethodName", 1, code); - } -} diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/w/util/DelegatingWriterRegistryTest.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/w/util/DelegatingWriterRegistryTest.java deleted file mode 100644 index 26f63f40f..000000000 --- a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/w/util/DelegatingWriterRegistryTest.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * 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.impl.trans.w.util; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; - -import io.fd.honeycomb.v3po.impl.trans.VppException; -import io.fd.honeycomb.v3po.impl.trans.w.VppWriter; -import io.fd.honeycomb.v3po.impl.trans.w.WriteContext; -import io.fd.honeycomb.v3po.impl.trans.w.WriterRegistry; -import io.fd.honeycomb.v3po.impl.trans.w.impl.CompositeRootVppWriter; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -public class DelegatingWriterRegistryTest { - - private final InstanceIdentifier vppId; - private final InstanceIdentifier vppStateId; - private final InstanceIdentifier interfaceId; - - private WriteContext ctx; - private CompositeRootVppWriter vppWriter; - private CompositeRootVppWriter vppStateWriter; - private CompositeRootVppWriter interfacesWriter; - - private DelegatingWriterRegistry registry; - - public DelegatingWriterRegistryTest() { - vppId = InstanceIdentifier.create(Vpp.class); - vppStateId = InstanceIdentifier.create(VppState.class); - interfaceId = InstanceIdentifier.create(Interfaces.class); - } - - @SuppressWarnings("unchecked") - private CompositeRootVppWriter mockWriter(Class clazz) { - final CompositeRootVppWriter mock = (CompositeRootVppWriter) Mockito.mock(CompositeRootVppWriter.class); - doReturn(InstanceIdentifier.create(clazz)).when(mock).getManagedDataObjectType(); - return mock; - } - - private DataObject mockDataObject(final String name, final Class classToMock) { - final DataObject dataBefore = mock(classToMock, name); - doReturn(classToMock).when(dataBefore).getImplementedInterface(); - return dataBefore; - } - - @SuppressWarnings("unchecked") - private static Map, DataObject> asMap(DataObject... objects) { - final Map, DataObject> map = new HashMap<>(); - for (DataObject object : objects) { - final Class implementedInterface = - (Class) object.getImplementedInterface(); - final InstanceIdentifier id = InstanceIdentifier.create(implementedInterface); - map.put(id, object); - } - return map; - } - - @Before - public void setUp() { - ctx = mock(WriteContext.class); - vppWriter = mockWriter(Vpp.class); - vppStateWriter = mockWriter(VppState.class); - interfacesWriter = mockWriter(Interfaces.class); - - final List> writers = new ArrayList<>(); - writers.add(vppWriter); - writers.add(vppStateWriter); - writers.add(interfacesWriter); - - registry = new DelegatingWriterRegistry(writers); - } - - @Test(expected = UnsupportedOperationException.class) - public void testGetManagedDataObjectType() { - registry.getManagedDataObjectType(); - } - - @Test - public void testBulkUpdateRevert() throws Exception { - // Prepare data changes: - final DataObject dataBefore1 = mockDataObject("Vpp before", Vpp.class); - final DataObject dataAfter1 = mockDataObject("Vpp after", Vpp.class); - - final DataObject dataBefore2 = mockDataObject("VppState before", VppState.class); - final DataObject dataAfter2 = mockDataObject("VppState after", VppState.class); - - // Fail on update - doThrow(new VppException("vpp failed")).when(vppStateWriter) - .update(vppStateId, dataBefore2, dataAfter2, ctx); - - // Run the test - try { - registry.update(asMap(dataBefore1, dataBefore2), asMap(dataAfter1, dataAfter2), ctx); - } catch (WriterRegistry.BulkUpdateException e) { - // Check second update failed - assertEquals(vppStateId, e.getFailedId()); - verify(vppWriter).update(vppId, dataBefore1, dataAfter1, ctx); - verify(vppStateWriter).update(vppStateId, dataBefore2, dataAfter2, ctx); - - // Try to revert changes - e.revertChanges(); - - // Check revert was successful - verify(vppWriter).update(vppId, dataAfter1, dataBefore1, ctx); - verify(vppStateWriter, never()).update(vppStateId, dataAfter2, dataBefore2, ctx); - - return; - } - fail("BulkUpdateException expected"); - } - - @Test - public void testBulkUpdateRevertFail() throws Exception { - // Prepare data changes: - final DataObject dataBefore1 = mockDataObject("Vpp before", Vpp.class); - final DataObject dataAfter1 = mockDataObject("Vpp after", Vpp.class); - - final DataObject dataBefore2 = mockDataObject("VppState before", VppState.class); - final DataObject dataAfter2 = mockDataObject("VppState after", VppState.class); - - final DataObject dataBefore3 = mockDataObject("Interfaces before", Interfaces.class); - final DataObject dataAfter3 = mockDataObject("Interfaces after", Interfaces.class); - - // Fail on the third update - doThrow(new VppException("vpp failed")).when(interfacesWriter) - .update(interfaceId, dataBefore3, dataAfter3, ctx); - - // Fail on the second revert - doThrow(new VppException("vpp failed again")).when(vppWriter) - .update(vppId, dataAfter1, dataBefore1, ctx); - - // Run the test - try { - registry.update(asMap(dataBefore1, dataBefore2, dataBefore3), asMap(dataAfter1, dataAfter2, dataAfter3), ctx); - } catch (WriterRegistry.BulkUpdateException e) { - // Check third update failed - assertEquals(interfaceId, e.getFailedId()); - verify(vppWriter).update(vppId, dataBefore1, dataAfter1, ctx); - verify(vppStateWriter).update(vppStateId, dataBefore2, dataAfter2, ctx); - verify(interfacesWriter).update(interfaceId, dataBefore3, dataAfter3, ctx); - - // Try to revert changes - try { - e.revertChanges(); - } catch (WriterRegistry.Reverter.RevertFailedException e2) { - // Check second revert failed - assertEquals(Collections.singletonList(vppId), e2.getNotRevertedChanges()); - verify(vppWriter).update(vppId, dataAfter1, dataBefore1, ctx); - verify(vppStateWriter).update(vppStateId, dataAfter2, dataBefore2, ctx); - verify(interfacesWriter, never()).update(interfaceId, dataAfter3, dataBefore3, ctx); - return; - } - fail("WriterRegistry.Revert.RevertFailedException expected"); - } - fail("BulkUpdateException expected"); - } -} \ No newline at end of file diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/w/util/TransactionWriteContextTest.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/w/util/TransactionWriteContextTest.java deleted file mode 100644 index 0f906d20c..000000000 --- a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/w/util/TransactionWriteContextTest.java +++ /dev/null @@ -1,122 +0,0 @@ -package io.fd.honeycomb.v3po.impl.trans.w.util; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -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.impl.trans.util.Context; -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.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; -import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; -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 TransactionWriteContextTest { - - @Mock - private BindingNormalizedNodeSerializer serializer; - @Mock - private DOMDataReadOnlyTransaction beforeTx; - @Mock - private DOMDataReadOnlyTransaction afterTx; - @Mock - private CheckedFuture>, ReadFailedException> future; - @Mock - private Optional> optional; - @Mock - private Map.Entry entry; - - private TransactionWriteContext transactionWriteContext; - - @Before - public void setUp() { - initMocks(this); - transactionWriteContext = new TransactionWriteContext(serializer, beforeTx, afterTx); - } - - @Test - public void testReadBeforeNoData() throws Exception { - when(beforeTx.read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn(future); - when(future.checkedGet()).thenReturn(optional); - when(optional.isPresent()).thenReturn(false); - - final InstanceIdentifier instanceId = - InstanceIdentifier.create(Vpp.class).child(BridgeDomains.class).child(BridgeDomain.class); - - final Optional dataObjects = transactionWriteContext.readBefore(instanceId); - assertNotNull(dataObjects); - assertFalse(dataObjects.isPresent()); - - verify(serializer).toYangInstanceIdentifier(instanceId); - verify(serializer, never()).fromNormalizedNode(any(YangInstanceIdentifier.class), any(NormalizedNode.class)); - } - - - @Test - public void testReadBefore() throws Exception { - when(beforeTx.read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn(future); - when(future.checkedGet()).thenReturn(optional); - when(optional.isPresent()).thenReturn(true); - - final InstanceIdentifier instanceId = - InstanceIdentifier.create(Vpp.class).child(BridgeDomains.class).child(BridgeDomain.class); - final YangInstanceIdentifier yangId = YangInstanceIdentifier.builder().node(VppState.QNAME).node( - BridgeDomains.QNAME).node(BridgeDomain.QNAME).build(); - when(serializer.toYangInstanceIdentifier(any(InstanceIdentifier.class))).thenReturn(yangId); - when(serializer.fromNormalizedNode(eq(yangId), any(NormalizedNode.class))).thenReturn(entry); - when(entry.getValue()).thenReturn(mock(DataObject.class)); - - final Optional dataObjects = transactionWriteContext.readBefore(instanceId); - assertNotNull(dataObjects); - assertTrue(dataObjects.isPresent()); - - verify(serializer).toYangInstanceIdentifier(instanceId); - verify(serializer).fromNormalizedNode(eq(yangId), any(NormalizedNode.class)); - } - - @Test(expected = IllegalStateException.class) - public void testReadBeforeFailed() throws Exception { - when(beforeTx.read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn(future); - when(future.checkedGet()).thenThrow(ReadFailedException.class); - transactionWriteContext.readBefore(mock(InstanceIdentifier.class)); - } - - @Test(expected = IllegalStateException.class) - public void testReadAfterFailed() throws Exception { - when(afterTx.read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn(future); - when(future.checkedGet()).thenThrow(ReadFailedException.class); - transactionWriteContext.readAfter(mock(InstanceIdentifier.class)); - } - - @Test - public void testGetContext() throws Exception { - assertNotNull(transactionWriteContext.getContext()); - } - - @Test - public void testClose() throws Exception { - final Context context = transactionWriteContext.getContext(); - transactionWriteContext.close(); - // TODO verify context was closed - } -} \ No newline at end of file diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainCustomizerTest.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainCustomizerTest.java deleted file mode 100644 index 4614b875a..000000000 --- a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainCustomizerTest.java +++ /dev/null @@ -1,269 +0,0 @@ -/* - * 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.impl.vpp; - -import static io.fd.honeycomb.v3po.impl.vpp.BridgeDomainTestUtils.BD_NAME_TO_ID_ANSWER; -import static io.fd.honeycomb.v3po.impl.vpp.BridgeDomainTestUtils.bdIdentifierForName; -import static io.fd.honeycomb.v3po.impl.vpp.BridgeDomainTestUtils.bdNameToID; -import static io.fd.honeycomb.v3po.impl.vpp.BridgeDomainTestUtils.booleanToByte; -import static io.fd.honeycomb.v3po.impl.vpp.BridgeDomainTestUtils.intToBoolean; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import io.fd.honeycomb.v3po.impl.trans.util.Context; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey; -import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; -import org.openvpp.vppjapi.vppApi; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor; -import org.powermock.modules.junit4.PowerMockRunner; - -@RunWith(PowerMockRunner.class) -@SuppressStaticInitializationFor("org.openvpp.vppjapi.vppConn") -@PrepareForTest(vppApi.class) -public class BridgeDomainCustomizerTest { - - private static final int RESPONSE_NOT_READY = -77; - private static final byte ADD_OR_UPDATE_BD = (byte) 1; - private static final byte ZERO = 0; - private vppApi api; - - @Mock - private Context ctx; - - private BridgeDomainCustomizer customizer; - - @Before - public void setUp() throws Exception { - // TODO create base class for tests using vppApi - api = PowerMockito.mock(vppApi.class); - initMocks(this); - customizer = new BridgeDomainCustomizer(api); - - PowerMockito.doAnswer(BD_NAME_TO_ID_ANSWER).when(api).findOrAddBridgeDomainId(anyString()); - PowerMockito.doAnswer(BD_NAME_TO_ID_ANSWER).when(api).bridgeDomainIdFromName(anyString()); - PowerMockito.when(api.getRetval(anyInt(), anyInt())).thenReturn(RESPONSE_NOT_READY).thenReturn(0); - PowerMockito.doReturn(0).when(api).getRetval(anyInt(), anyInt()); - } - - private BridgeDomain generateBridgeDomain(final String bdName) { - final byte arpTerm = 0; - final byte flood = 1; - final byte forward = 0; - final byte learn = 1; - final byte uuf = 0; - return generateBridgeDomain(bdName, arpTerm, flood, forward, learn, uuf); - } - - private BridgeDomain generateBridgeDomain(final String bdName, final int arpTerm, final int flood, - final int forward, final int learn, final int uuf) { - return new BridgeDomainBuilder() - .setName(bdName) - .setArpTermination(intToBoolean(arpTerm)) - .setFlood(intToBoolean(flood)) - .setForward(intToBoolean(forward)) - .setLearn(intToBoolean(learn)) - .setUnknownUnicastFlood(intToBoolean(uuf)) - .build(); - } - - private final int verifyBridgeDomainAddOrUpdateWasInvoked(final BridgeDomain bd) { - final int bdn1Id = bdNameToID(bd.getName()); - final byte arpTerm = booleanToByte(bd.isArpTermination()); - final byte flood = booleanToByte(bd.isFlood()); - final byte forward = booleanToByte(bd.isForward()); - final byte learn = booleanToByte(bd.isLearn()); - final byte uuf = booleanToByte(bd.isUnknownUnicastFlood()); - return verify(api).bridgeDomainAddDel(bdn1Id, flood, forward, learn, uuf, arpTerm, ADD_OR_UPDATE_BD); - } - - private int verifyBridgeDomainAddOrUpdateWasNotInvoked(final BridgeDomain bd) { - final int bdn1Id = bdNameToID(bd.getName()); - final byte arpTerm = booleanToByte(bd.isArpTermination()); - final byte flood = booleanToByte(bd.isFlood()); - final byte forward = booleanToByte(bd.isForward()); - final byte learn = booleanToByte(bd.isLearn()); - final byte uuf = booleanToByte(bd.isUnknownUnicastFlood()); - return verify(api, never()).bridgeDomainAddDel(bdn1Id, flood, forward, learn, uuf, arpTerm, ADD_OR_UPDATE_BD); - } - - private int verifyBridgeDomainDeletedWasInvoked(final BridgeDomain bd) { - final int bdn1Id = bdNameToID(bd.getName()); - return verify(api).bridgeDomainAddDel(bdn1Id, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO); - } - - private int verifyBridgeDomainDeletedWasNotInvoked(final BridgeDomain bd) { - final int bdn1Id = bdNameToID(bd.getName()); - return verify(api, never()).bridgeDomainAddDel(bdn1Id, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO); - } - - @Test - public void testAddBridgeDomain() { - final String bdName = "bd1"; - final BridgeDomain bd = generateBridgeDomain("bd1"); - - customizer.writeCurrentAttributes(bdIdentifierForName(bdName), bd, ctx); - - verifyBridgeDomainAddOrUpdateWasInvoked(bd); - } - - @Test - public void testBridgeDomainNameCreateFailed() { - final String bdName = "bd1"; - final BridgeDomain bd = generateBridgeDomain("bd1"); - - // make vpp api fail to create id for our bd name - PowerMockito.doReturn(-1).when(api).findOrAddBridgeDomainId(bdName); - - try { - customizer.writeCurrentAttributes(bdIdentifierForName(bdName), bd, ctx); - } catch (IllegalStateException e) { - verifyBridgeDomainAddOrUpdateWasNotInvoked(bd); - return; - } - fail("IllegalStateException was expected"); - } - - @Test - public void testAddBridgeDomainFailed() { - // make any call to vpp fail - PowerMockito.doReturn(-1).when(api).getRetval(anyInt(), anyInt()); - - final String bdName = "bd1"; - final BridgeDomain bd = generateBridgeDomain(bdName); - - try { - customizer.writeCurrentAttributes(bdIdentifierForName(bdName), bd, ctx); - } catch (IllegalStateException e) { - verifyBridgeDomainAddOrUpdateWasInvoked(bd); - return; - } - fail("IllegalStateException was expected"); - } - - @Test - public void testDeleteBridgeDomain() { - final String bdName = "bd1"; - final BridgeDomain bd = generateBridgeDomain("bd1"); - - customizer.deleteCurrentAttributes(bdIdentifierForName(bdName), bd, ctx); - - verifyBridgeDomainDeletedWasInvoked(bd); - } - - @Test - public void testDeleteUnknownBridgeDomain() { - final String bdName = "bd1"; - final BridgeDomain bd = generateBridgeDomain("bd1"); - - // make vpp api not find our bd - PowerMockito.doReturn(-1).when(api).bridgeDomainIdFromName(bdName); - - try { - customizer.deleteCurrentAttributes(bdIdentifierForName(bdName), bd, ctx); - } catch (IllegalStateException e) { - verifyBridgeDomainDeletedWasNotInvoked(bd); - return; - } - fail("IllegalStateException was expected"); - } - - @Test - public void testDeleteBridgeDomainFailed() { - // make any call to vpp fail - PowerMockito.doReturn(-1).when(api).getRetval(anyInt(), anyInt()); - - final String bdName = "bd1"; - final BridgeDomain bd = generateBridgeDomain(bdName); - - try { - customizer.deleteCurrentAttributes(bdIdentifierForName(bdName), bd, ctx); - } catch (IllegalStateException e) { - verifyBridgeDomainDeletedWasInvoked(bd); - return; - } - fail("IllegalStateException was expected"); - } - - @Test - public void testUpdateBridgeDomain() throws Exception { - final String bdName = "bd1"; - final byte arpTermBefore = 1; - final byte floodBefore = 1; - final byte forwardBefore = 0; - final byte learnBefore = 1; - final byte uufBefore = 0; - - final BridgeDomain dataBefore = - generateBridgeDomain(bdName, arpTermBefore, floodBefore, forwardBefore, learnBefore, uufBefore); - final BridgeDomain dataAfter = - generateBridgeDomain(bdName, arpTermBefore ^ 1, floodBefore ^ 1, forwardBefore ^ 1, learnBefore ^ 1, - uufBefore ^ 1); - - final KeyedInstanceIdentifier id = bdIdentifierForName(bdName); - - customizer.updateCurrentAttributes(id, dataBefore, dataAfter, ctx); - - verifyBridgeDomainAddOrUpdateWasInvoked(dataAfter); - } - - @Test - public void testUpdateUnknownBridgeDomain() throws Exception { - final String bdName = "bd1"; - final BridgeDomain bd = generateBridgeDomain("bd1"); - - // make vpp api not find our bd - PowerMockito.doReturn(-1).when(api).bridgeDomainIdFromName(bdName); - - try { - customizer.updateCurrentAttributes(bdIdentifierForName(bdName), bd, bd, ctx); - } catch (IllegalStateException e) { - verifyBridgeDomainAddOrUpdateWasNotInvoked(bd); - return; - } - fail("IllegalStateException was expected"); - } - - @Test - public void testUpdateBridgeDomainFailed() { - // make any call to vpp fail - PowerMockito.doReturn(-1).when(api).getRetval(anyInt(), anyInt()); - - final String bdName = "bd1"; - final BridgeDomain bd = generateBridgeDomain(bdName); - - try { - customizer.updateCurrentAttributes(bdIdentifierForName(bdName), bd, bd, ctx); - } catch (IllegalStateException e) { - verifyBridgeDomainAddOrUpdateWasInvoked(bd); - return; - } - fail("IllegalStateException was expected"); - } - -} \ No newline at end of file diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainTestUtils.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainTestUtils.java deleted file mode 100644 index 6930493b6..000000000 --- a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainTestUtils.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.impl.vpp; - -import javax.annotation.Nullable; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; - -final class BridgeDomainTestUtils { - - private BridgeDomainTestUtils() { - throw new UnsupportedOperationException("Utility class cannot be instantiated."); - } - - public static byte booleanToByte(@Nullable final Boolean value) { - return value != null && value ? (byte) 1 : (byte) 0; - } - - @Nullable - public static Boolean intToBoolean(final int value) { - if (value == 0) { - return Boolean.FALSE; - } - if (value == 1) { - return Boolean.TRUE; - } - return null; - } - - public static int bdNameToID(String bName) { - return Integer.parseInt(((Character)bName.charAt(bName.length() - 1)).toString()); - } - - public static KeyedInstanceIdentifier bdIdentifierForName( - final String bdName) { - return InstanceIdentifier.create(BridgeDomains.class).child(BridgeDomain.class, new BridgeDomainKey(bdName)); - } - - public static final Answer BD_NAME_TO_ID_ANSWER = new Answer() { - @Override - public Integer answer(final InvocationOnMock invocationOnMock) throws Throwable { - return bdNameToID((String) invocationOnMock.getArguments()[0]); - } - }; -} \ No newline at end of file diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/VppTest.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/VppTest.java deleted file mode 100644 index c9533a0e7..000000000 --- a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/VppTest.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * 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.impl.vpp; - -import static io.fd.honeycomb.v3po.impl.vpp.BridgeDomainTestUtils.BD_NAME_TO_ID_ANSWER; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; - -import com.google.common.collect.Lists; -import io.fd.honeycomb.v3po.impl.trans.w.VppWriter; -import io.fd.honeycomb.v3po.impl.trans.w.WriteContext; -import io.fd.honeycomb.v3po.impl.trans.w.impl.CompositeRootVppWriter; -import io.fd.honeycomb.v3po.impl.trans.w.util.DelegatingWriterRegistry; -import java.util.Collections; -import java.util.List; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomainsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainBuilder; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.vppjapi.vppApi; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor; -import org.powermock.modules.junit4.PowerMockRunner; - -@RunWith(PowerMockRunner.class) -@SuppressStaticInitializationFor("org.openvpp.vppjapi.vppConn") -@PrepareForTest(vppApi.class) -public class VppTest { - - private vppApi api; - private DelegatingWriterRegistry rootRegistry; - private CompositeRootVppWriter vppWriter; - private WriteContext ctx; - - final byte zero = (byte) 0; - final byte flood = (byte) 1; - final byte forward = (byte) 0; - final byte learn = (byte) 1; - final byte uuf = (byte) 0; - final byte arpTerm = (byte) 0; - final byte add = (byte) 1; - - @Before - public void setUp() throws Exception { - api = PowerMockito.mock(vppApi.class); - ctx = mock(WriteContext.class); - PowerMockito.doAnswer(BD_NAME_TO_ID_ANSWER).when(api).findOrAddBridgeDomainId(anyString()); - PowerMockito.doAnswer(BD_NAME_TO_ID_ANSWER).when(api).bridgeDomainIdFromName(anyString()); - PowerMockito.doReturn(1).when(api).getRetval(anyInt(), anyInt()); - vppWriter = VppUtils.getVppWriter(api); - rootRegistry = new DelegatingWriterRegistry( - Collections.>singletonList(vppWriter)); - } - - @Test - public void writeVpp() throws Exception { - rootRegistry.update( - InstanceIdentifier.create(Vpp.class), - null, - new VppBuilder().setBridgeDomains(getBridgeDomains("bdn1")).build(), - ctx); - - verify(api).bridgeDomainAddDel(1, flood, forward, learn, uuf, arpTerm, add); - - vppWriter.update(InstanceIdentifier.create(Vpp.class), - null, - new VppBuilder().setBridgeDomains(getBridgeDomains("bdn1")).build(), - ctx); - - verify(api, times(2)).bridgeDomainAddDel(1, flood, forward, learn, uuf, arpTerm, add); - } - - @Test - public void writeVppFromRoot() throws Exception { - final Vpp vpp = new VppBuilder().setBridgeDomains(getBridgeDomains("bdn1")).build(); - - rootRegistry.update(Collections., DataObject>emptyMap(), - Collections., DataObject>singletonMap(InstanceIdentifier.create(Vpp.class), - vpp), ctx); - - verify(api).bridgeDomainAddDel(1, flood, forward, learn, uuf, arpTerm, add); - } - - private BridgeDomains getBridgeDomains(String... name) { - final List bdmns = Lists.newArrayList(); - for (String s : name) { - bdmns.add(new BridgeDomainBuilder() - .setName(s) - .setArpTermination(false) - .setFlood(true) - .setForward(false) - .setLearn(true) - .build()); - } - return new BridgeDomainsBuilder() - .setBridgeDomain(bdmns) - .build(); - } - - @Test - public void deleteVpp() throws Exception { - rootRegistry.update( - InstanceIdentifier.create(Vpp.class), - new VppBuilder().setBridgeDomains(getBridgeDomains("bdn1")).build(), - null, - ctx); - - final byte zero = (byte) 0; - - verify(api).bridgeDomainAddDel(1, zero, zero, zero, zero, zero, zero); - } - - @Test - public void updateVppNoActualChange() throws Exception { - rootRegistry.update( - InstanceIdentifier.create(Vpp.class), - new VppBuilder().setBridgeDomains(getBridgeDomains("bdn1")).build(), - new VppBuilder().setBridgeDomains(getBridgeDomains("bdn1")).build(), - ctx); - - verifyZeroInteractions(api); - } - - @Test - public void writeUpdate() throws Exception { - final BridgeDomains domainsBefore = getBridgeDomains("bdn1"); - final BridgeDomain bdn1Before = domainsBefore.getBridgeDomain().get(0); - - final BridgeDomain bdn1After = new BridgeDomainBuilder(bdn1Before).setFlood(!bdn1Before.isFlood()).build(); - final BridgeDomains domainsAfter = new BridgeDomainsBuilder() - .setBridgeDomain(Collections.singletonList(bdn1After)) - .build(); - - rootRegistry.update( - InstanceIdentifier.create(Vpp.class), - new VppBuilder().setBridgeDomains(domainsBefore).build(), - new VppBuilder().setBridgeDomains(domainsAfter).build(), - ctx); - - final int bdn1Id = 1; - - // bdn1 is created with negated flood value - verify(api).bridgeDomainAddDel(bdn1Id, (byte) (flood ^ 1), forward, learn, uuf, arpTerm, add); - } - - // TODO test unkeyed list - // TODO test update of a child without dedicated writer -} \ No newline at end of file diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/VppUtils.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/VppUtils.java deleted file mode 100644 index d73a8732c..000000000 --- a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/VppUtils.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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.impl.vpp; - -import io.fd.honeycomb.v3po.impl.trans.util.VppRWUtils; -import io.fd.honeycomb.v3po.impl.trans.w.ChildVppWriter; -import io.fd.honeycomb.v3po.impl.trans.w.impl.CompositeChildVppWriter; -import io.fd.honeycomb.v3po.impl.trans.w.impl.CompositeListVppWriter; -import io.fd.honeycomb.v3po.impl.trans.w.impl.CompositeRootVppWriter; -import io.fd.honeycomb.v3po.impl.trans.w.util.NoopWriterCustomizer; -import io.fd.honeycomb.v3po.impl.trans.w.util.ReflexiveChildWriterCustomizer; -import java.util.ArrayList; -import java.util.List; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey; -import org.opendaylight.yangtools.yang.binding.ChildOf; -import org.openvpp.vppjapi.vppApi; - -final class VppUtils { - - public VppUtils() {} - - /** - * Create root Vpp writer with all its children wired - */ - static CompositeRootVppWriter getVppWriter(@Nonnull final vppApi vppApi) { - - final CompositeListVppWriter bridgeDomainWriter = new CompositeListVppWriter<>( - BridgeDomain.class, - new io.fd.honeycomb.v3po.impl.vpp.BridgeDomainCustomizer(vppApi)); - - final ChildVppWriter bridgeDomainsReader = new CompositeChildVppWriter<>( - BridgeDomains.class, - VppRWUtils.singletonChildWriterList(bridgeDomainWriter), - new ReflexiveChildWriterCustomizer()); - - final List>> childWriters = new ArrayList<>(); - childWriters.add(bridgeDomainsReader); - - return new CompositeRootVppWriter<>( - Vpp.class, - childWriters, - new NoopWriterCustomizer()); - } -} diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vppstate/VppStateTest.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vppstate/VppStateTest.java deleted file mode 100644 index 5cb678e3a..000000000 --- a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vppstate/VppStateTest.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * 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.impl.vppstate; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.mock; - -import com.google.common.base.Optional; -import com.google.common.base.Predicate; -import com.google.common.collect.Iterables; -import com.google.common.collect.Multimap; -import io.fd.honeycomb.v3po.impl.trans.r.ReadContext; -import io.fd.honeycomb.v3po.impl.trans.r.VppReader; -import io.fd.honeycomb.v3po.impl.trans.r.impl.CompositeListVppReader; -import io.fd.honeycomb.v3po.impl.trans.r.impl.CompositeRootVppReader; -import io.fd.honeycomb.v3po.impl.trans.r.util.DelegatingReaderRegistry; -import java.util.Collections; -import java.util.List; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Matchers; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppStateBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomains; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.Version; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.VersionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.L2Fib; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.L2FibKey; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.vppjapi.vppApi; -import org.openvpp.vppjapi.vppBridgeDomainDetails; -import org.openvpp.vppjapi.vppBridgeDomainInterfaceDetails; -import org.openvpp.vppjapi.vppL2Fib; -import org.openvpp.vppjapi.vppVersion; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor; -import org.powermock.modules.junit4.PowerMockRunner; - -@RunWith(PowerMockRunner.class) -@SuppressStaticInitializationFor("org.openvpp.vppjapi.vppConn") -@PrepareForTest(vppApi.class) -public class VppStateTest { - - public static final vppVersion VERSION = new vppVersion("test", "1", "2", "33"); - - private vppApi api; - private CompositeRootVppReader vppStateReader; - private DelegatingReaderRegistry readerRegistry; - private vppBridgeDomainDetails bdDetails; - private vppBridgeDomainDetails bdDetails2; - private ReadContext ctx; - - @Before - public void setUp() throws Exception { - api = PowerMockito.mock(vppApi.class); - - ctx = mock(ReadContext.class); - - bdDetails = new vppBridgeDomainDetails(); - setIfcs(bdDetails); - setBaseAttrs(bdDetails, "bdn1", 1); - - bdDetails2 = new vppBridgeDomainDetails(); - setIfcs(bdDetails2); - setBaseAttrs(bdDetails2, "bdn2", 2); - - final vppL2Fib[] l2Fibs = getL2Fibs(); - PowerMockito.doReturn(l2Fibs).when(api).l2FibTableDump(Matchers.anyInt()); - PowerMockito.doAnswer(new Answer() { - - @Override - public vppBridgeDomainDetails answer(final InvocationOnMock invocationOnMock) throws Throwable { - final Integer idx = (Integer) invocationOnMock.getArguments()[0]; - switch (idx) { - case 1 : return bdDetails; - case 2 : return bdDetails2; - default: return null; - } - } - }).when(api).getBridgeDomainDetails(Matchers.anyInt()); - - PowerMockito.doAnswer(new Answer() { - @Override - public Object answer(final InvocationOnMock invocationOnMock) throws Throwable { - final String name = (String) invocationOnMock.getArguments()[0]; - switch (name) { - case "bdn1" : return 1; - case "bdn2" : return 2; - default: return null; - } - } - }).when(api).bridgeDomainIdFromName(anyString()); - PowerMockito.doReturn(new int[] {1, 2}).when(api).bridgeDomainDump(Matchers.anyInt()); - PowerMockito.doReturn(VERSION).when(api).getVppVersion(); - vppStateReader = VppStateUtils.getVppStateReader(api); - readerRegistry = new DelegatingReaderRegistry(Collections.>singletonList(vppStateReader)); - } - - private vppL2Fib[] getL2Fibs() { - return new vppL2Fib[] { - new vppL2Fib(new byte[]{1,2,3,4,5,6}, true, "ifc1", true, true), - new vppL2Fib(new byte[]{2,2,3,4,5,6}, true, "ifc2", true, true), - }; - } - - private void setIfcs(final vppBridgeDomainDetails bdDetails) { - final vppBridgeDomainInterfaceDetails ifcDetails = new vppBridgeDomainInterfaceDetails(); - ifcDetails.interfaceName = "ifc"; - ifcDetails.splitHorizonGroup = 2; - bdDetails.interfaces = new vppBridgeDomainInterfaceDetails[] {ifcDetails}; - } - - private void setBaseAttrs(final vppBridgeDomainDetails bdDetails, final String bdn, final int i) { - bdDetails.name = bdn; - bdDetails.arpTerm = true; - bdDetails.bdId = i; - bdDetails.bviInterfaceName = "ifc"; - bdDetails.flood = true; - bdDetails.forward = true; - bdDetails.learn = true; - bdDetails.uuFlood = true; - } - - @Test - public void testReadAll() throws Exception { - final Multimap, ? extends DataObject> dataObjects = readerRegistry.readAll(ctx); - assertEquals(dataObjects.size(), 1); - final DataObject dataObject = Iterables.getOnlyElement(dataObjects.get(Iterables.getOnlyElement(dataObjects.keySet()))); - assertTrue(dataObject instanceof VppState); - assertVersion((VppState) dataObject); - assertEquals(2, ((VppState) dataObject).getBridgeDomains().getBridgeDomain().size()); - } - - private void assertVersion(final VppState dataObject) { - assertEquals( - new VersionBuilder() - .setName("test") - .setBuildDirectory("1") - .setBranch("2") - .setBuildDate("33") - .build(), - dataObject.getVersion()); - } - - @Test - public void testReadSpecific() throws Exception { - final Optional read = readerRegistry.read(InstanceIdentifier.create(VppState.class), ctx); - assertTrue(read.isPresent()); - assertVersion((VppState) read.get()); - } - - @Test - public void testReadBridgeDomains() throws Exception { - VppState readRoot = (VppState) readerRegistry.read(InstanceIdentifier.create(VppState.class), ctx).get(); - - Optional read = - readerRegistry.read(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class), ctx); - assertTrue(read.isPresent()); - assertEquals(readRoot.getBridgeDomains(), read.get()); - } - - /** - * L2fib does not have a dedicated reader, relying on auto filtering - */ - @Test - public void testReadL2Fib() throws Exception { - // Deep child without a dedicated reader with specific l2fib key - Optional read = - readerRegistry.read(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child( - BridgeDomain.class, new BridgeDomainKey("bdn1")) - .child(L2Fib.class, new L2FibKey(new PhysAddress("01:02:03:04:05:06"))), ctx); - assertTrue(read.isPresent()); - - // non existing l2fib - read = - readerRegistry.read(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child( - BridgeDomain.class, new BridgeDomainKey("bdn1")) - .child(L2Fib.class, new L2FibKey(new PhysAddress("FF:FF:FF:04:05:06"))), ctx); - assertFalse(read.isPresent()); - } - - @Test - public void testReadBridgeDomainAll() throws Exception { - VppState readRoot = (VppState) readerRegistry.read(InstanceIdentifier.create(VppState.class), ctx).get(); - - final CompositeListVppReader bridgeDomainReader = - VppStateUtils.getBridgeDomainReader(api); - - final List read = - bridgeDomainReader.readList(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child( - BridgeDomain.class), ctx); - - assertEquals(readRoot.getBridgeDomains().getBridgeDomain(), read); - } - - @Test - public void testReadBridgeDomain() throws Exception { - VppState readRoot = (VppState) readerRegistry.read(InstanceIdentifier.create(VppState.class), ctx).get(); - - final Optional read = - readerRegistry.read(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child( - BridgeDomain.class, new BridgeDomainKey("bdn1")), ctx); - - assertTrue(read.isPresent()); - assertEquals(Iterables.find(readRoot.getBridgeDomains().getBridgeDomain(), new Predicate() { - @Override - public boolean apply(final BridgeDomain input) { - return input.getKey().getName().equals("bdn1"); - } - }), read.get()); - } - - // FIXME - @Ignore("Bridge domain customizer does not check whether the bd exists or not and fails with NPE, add it there") - @Test - public void testReadBridgeDomainNotExisting() throws Exception { - final Optional read = - readerRegistry.read(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child( - BridgeDomain.class, new BridgeDomainKey("NOT EXISTING")), ctx); - assertFalse(read.isPresent()); - } - - @Test - public void testReadVersion() throws Exception { - VppState readRoot = (VppState) readerRegistry.read(InstanceIdentifier.create(VppState.class), ctx).get(); - - Optional read = - readerRegistry.read(InstanceIdentifier.create(VppState.class).child(Version.class), ctx); - assertTrue(read.isPresent()); - assertEquals(readRoot.getVersion(), read.get()); - } -} \ No newline at end of file diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vppstate/VppStateUtils.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vppstate/VppStateUtils.java deleted file mode 100644 index 73113174c..000000000 --- a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vppstate/VppStateUtils.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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.impl.vppstate; - -import io.fd.honeycomb.v3po.impl.trans.r.ChildVppReader; -import io.fd.honeycomb.v3po.impl.trans.r.impl.CompositeChildVppReader; -import io.fd.honeycomb.v3po.impl.trans.r.impl.CompositeListVppReader; -import io.fd.honeycomb.v3po.impl.trans.r.impl.CompositeRootVppReader; -import io.fd.honeycomb.v3po.impl.trans.r.util.ReflexiveChildReaderCustomizer; -import io.fd.honeycomb.v3po.impl.trans.r.util.ReflexiveRootReaderCustomizer; -import io.fd.honeycomb.v3po.impl.trans.util.VppRWUtils; -import java.util.ArrayList; -import java.util.List; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppStateBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomains; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomainsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.Version; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainKey; -import org.opendaylight.yangtools.yang.binding.ChildOf; -import org.openvpp.vppjapi.vppApi; - -final class VppStateUtils { - - public VppStateUtils() {} - - /** - * Create root VppState reader with all its children wired - */ - static CompositeRootVppReader getVppStateReader(@Nonnull final vppApi vppApi) { - - final ChildVppReader versionReader = new CompositeChildVppReader<>( - Version.class, new VersionCustomizer(vppApi)); - - final CompositeListVppReader bridgeDomainReader = - getBridgeDomainReader(vppApi); - - final ChildVppReader bridgeDomainsReader = new CompositeChildVppReader<>( - BridgeDomains.class, - VppRWUtils.singletonChildReaderList(bridgeDomainReader), - new ReflexiveChildReaderCustomizer<>(BridgeDomainsBuilder.class)); - - final List>> childVppReaders = new ArrayList<>(); - childVppReaders.add(versionReader); - childVppReaders.add(bridgeDomainsReader); - - return new CompositeRootVppReader<>( - VppState.class, - childVppReaders, - VppRWUtils.emptyAugReaderList(), - new ReflexiveRootReaderCustomizer<>(VppStateBuilder.class)); - } - - static CompositeListVppReader getBridgeDomainReader( - final @Nonnull vppApi vppApi) { - return new CompositeListVppReader<>( - BridgeDomain.class, - new BridgeDomainCustomizer(vppApi)); - } -} diff --git a/v3po/pom.xml b/v3po/pom.xml index ef721352d..cb9073c9b 100644 --- a/v3po/pom.xml +++ b/v3po/pom.xml @@ -33,6 +33,11 @@ api + vpp-facade-spi + vpp-facade-api + vpp-facade-impl + vpp-facade-utils + v3po2vpp impl karaf features diff --git a/v3po/v3po2vpp/pom.xml b/v3po/v3po2vpp/pom.xml new file mode 100644 index 000000000..eb4aca7fa --- /dev/null +++ b/v3po/v3po2vpp/pom.xml @@ -0,0 +1,92 @@ + + + + + io.fd.honeycomb.common + api-parent + 1.0.0-SNAPSHOT + ../../common/api-parent + + + 4.0.0 + io.fd.honeycomb.v3po + v3po2vpp + 1.0.0-SNAPSHOT + bundle + + + + ${project.groupId} + vpp-facade-spi + ${project.version} + + + ${project.groupId} + vpp-facade-utils + ${project.version} + + + ${project.groupId} + v3po-api + ${project.version} + + + io.fd.vpp + vppjapi + 1.0.0-SNAPSHOT + + + + + ${project.groupId} + vpp-facade-impl + ${project.version} + test + + + junit + junit + test + + + org.mockito + mockito-all + test + + + + org.powermock + powermock-api-mockito + 1.5.6 + test + + + org.powermock + powermock-module-junit4 + 1.5.6 + test + + + org.skinny-framework + skinny-logback + 1.0.8 + test + + + + + diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vpp/BridgeDomainCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vpp/BridgeDomainCustomizer.java new file mode 100644 index 000000000..2c394fe77 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vpp/BridgeDomainCustomizer.java @@ -0,0 +1,138 @@ +/* + * 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.facade.v3po.vpp; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +import io.fd.honeycomb.v3po.vpp.facade.impl.util.VppApiCustomizer; +import io.fd.honeycomb.v3po.vpp.facade.Context; +import io.fd.honeycomb.v3po.vpp.facade.spi.write.ListVppWriterCustomizer; +import java.util.List; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class BridgeDomainCustomizer + extends VppApiCustomizer + implements ListVppWriterCustomizer { + + private static final Logger LOG = LoggerFactory.getLogger(BridgeDomainCustomizer.class); + + private static final byte ADD_OR_UPDATE_BD = (byte) 1; + private static final int RESPONSE_NOT_READY = -77; + private static final int RELEASE = 1; + + public BridgeDomainCustomizer(final org.openvpp.vppjapi.vppApi api) { + super(api); + } + + @Nonnull + @Override + public List extract(@Nonnull final InstanceIdentifier currentId, + @Nonnull final DataObject parentData) { + return ((BridgeDomains) parentData).getBridgeDomain(); + } + + private int waitForResponse(final int ctxId) { + int rv; + while ((rv = getVppApi().getRetval(ctxId, RELEASE)) == RESPONSE_NOT_READY) { + // TODO limit attempts + } + return rv; + } + + private int addOrUpdateBridgeDomain(final int bdId, @Nonnull final BridgeDomain bd) { + byte flood = booleanToByte(bd.isFlood()); + byte forward = booleanToByte(bd.isForward()); + byte learn = booleanToByte(bd.isLearn()); + byte uuf = booleanToByte(bd.isUnknownUnicastFlood()); + byte arpTerm = booleanToByte(bd.isArpTermination()); + + int ctxId = getVppApi().bridgeDomainAddDel(bdId, flood, forward, learn, uuf, arpTerm, ADD_OR_UPDATE_BD); + return waitForResponse(ctxId); + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final BridgeDomain current, + @Nonnull final Context ctx) { + LOG.debug("writeCurrentAttributes: id={}, current={}, ctx={}", id, current, ctx); + final String bdName = current.getName(); + int bdId = getVppApi().findOrAddBridgeDomainId(bdName); + checkState(bdId > 0, "Unable to find or create bridge domain. Return code: %s", bdId); + + int rv = addOrUpdateBridgeDomain(bdId, current); + + checkState(rv >= 0, "Bridge domain %s(%s) write failed. Return code: %s", bdName, bdId, rv); + LOG.debug("Bridge domain {} written as {} successfully", bdName, bdId); + } + + private byte booleanToByte(@Nullable final Boolean aBoolean) { + return aBoolean != null && aBoolean ? (byte) 1 : (byte) 0; + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final BridgeDomain dataBefore, + @Nonnull final Context ctx) { + LOG.debug("deleteCurrentAttributes: id={}, dataBefore={}, ctx={}", id, dataBefore, ctx); + String bdName = id.firstKeyOf(BridgeDomain.class).getName(); + + int bdId = getVppApi().bridgeDomainIdFromName(bdName); + checkState(bdId > 0, "Unable to delete bridge domain. Does not exist. Return code: %s", bdId); + + int ctxId = getVppApi().bridgeDomainAddDel(bdId, + (byte) 0 /* flood */, + (byte) 0 /* forward */, + (byte) 0 /* learn */, + (byte) 0 /* uuf */, + (byte) 0 /* arpTerm */, + (byte) 0 /* isAdd */); + + int rv = waitForResponse(ctxId); + + checkState(rv >= 0, "Bridge domain delete failed. Return code: %s", rv); + LOG.debug("Bridge domain {} deleted as {} successfully", bdName, bdId); + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final BridgeDomain dataBefore, @Nonnull final BridgeDomain dataAfter, + @Nonnull final Context ctx) { + LOG.debug("updateCurrentAttributes: id={}, dataBefore={}, dataAfter={}, ctx={}", id, dataBefore, dataAfter, ctx); + + final String bdName = checkNotNull(dataAfter.getName()); + checkArgument(bdName.equals(dataBefore.getName()), "BridgeDomain name changed. It should be deleted and then created."); + + int bdId = getVppApi().bridgeDomainIdFromName(bdName); + checkState(bdId > 0, "Unable to find bridge domain. Return code: %s", bdId); + + final int rv = addOrUpdateBridgeDomain(bdId, dataAfter); + + checkState(rv >= 0, "Bridge domain %s(%s) update failed. Return code: %s", bdName, bdId, rv); + LOG.debug("Bridge domain {}({}) updated successfully", bdName, bdId); + } + +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vppstate/BridgeDomainCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vppstate/BridgeDomainCustomizer.java new file mode 100644 index 000000000..178deaddf --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vppstate/BridgeDomainCustomizer.java @@ -0,0 +1,136 @@ +/* + * 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.facade.v3po.vppstate; + +import com.google.common.collect.Lists; +import io.fd.honeycomb.v3po.vpp.facade.impl.util.VppApiCustomizer; +import io.fd.honeycomb.v3po.vpp.facade.Context; +import io.fd.honeycomb.v3po.vpp.facade.spi.read.ListVppReaderCustomizer; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomainsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.Interface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.InterfaceBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.L2Fib; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.L2FibBuilder; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.vppjapi.vppBridgeDomainDetails; +import org.openvpp.vppjapi.vppBridgeDomainInterfaceDetails; +import org.openvpp.vppjapi.vppL2Fib; + +public final class BridgeDomainCustomizer extends VppApiCustomizer + implements ListVppReaderCustomizer { + + public BridgeDomainCustomizer(@Nonnull final org.openvpp.vppjapi.vppApi vppApi) { + super(vppApi); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final BridgeDomainBuilder builder, @Nonnull final Context context) { + final BridgeDomainKey key = id.firstKeyOf(id.getTargetType()); + // TODO find out if bd exists based on name and if not return + + final int bdId = getVppApi().bridgeDomainIdFromName(key.getName()); + final vppBridgeDomainDetails bridgeDomainDetails = getVppApi().getBridgeDomainDetails(bdId); + + builder.setName(key.getName()); + // builder.setName(bridgeDomainDetails.name); + builder.setArpTermination(bridgeDomainDetails.arpTerm); + builder.setFlood(bridgeDomainDetails.flood); + builder.setForward(bridgeDomainDetails.forward); + builder.setLearn(bridgeDomainDetails.learn); + builder.setUnknownUnicastFlood(bridgeDomainDetails.uuFlood); + + builder.setInterface(getIfcs(bridgeDomainDetails)); + + final vppL2Fib[] vppL2Fibs = getVppApi().l2FibTableDump(bdId); + + final List l2Fibs = Lists.newArrayListWithCapacity(vppL2Fibs.length); + for (vppL2Fib vppL2Fib : vppL2Fibs) { + l2Fibs.add(new L2FibBuilder() + .setAction((vppL2Fib.filter + ? L2Fib.Action.Filter + : L2Fib.Action.Forward)) + .setBridgedVirtualInterface(vppL2Fib.bridgedVirtualInterface) + .setOutgoingInterface(vppL2Fib.outgoingInterface) + .setPhysAddress(new PhysAddress(getMacAddress(vppL2Fib.physAddress))) + .setStaticConfig(vppL2Fib.staticConfig) + .build()); + } + builder.setL2Fib(l2Fibs); + } + + private static String getMacAddress(byte[] mac) { + StringBuilder sb = new StringBuilder(18); + for (byte b : mac) { + if (sb.length() > 0) { + sb.append(':'); + } + sb.append(String.format("%02x", b)); + } + return sb.toString(); + } + + private List getIfcs(final vppBridgeDomainDetails bridgeDomainDetails) { + final List ifcs = new ArrayList<>(bridgeDomainDetails.interfaces.length); + for (vppBridgeDomainInterfaceDetails anInterface : bridgeDomainDetails.interfaces) { + ifcs.add(new InterfaceBuilder() + .setBridgedVirtualInterface(bridgeDomainDetails.bviInterfaceName.equals(anInterface.interfaceName)) + .setName(anInterface.interfaceName) + .setKey(new InterfaceKey(anInterface.interfaceName)) + .build()); + } + return ifcs; + } + + @Nonnull + @Override + public BridgeDomainBuilder getBuilder(@Nonnull final InstanceIdentifier id) { + return new BridgeDomainBuilder(); + } + + @Nonnull + @Override + public List getAllIds(@Nonnull final InstanceIdentifier id, @Nonnull final Context context) { + final int[] bIds = getVppApi().bridgeDomainDump(-1); + final List allIds = new ArrayList<>(bIds.length); + for (int bId : bIds) { + // FIXME this is highly inefficient having to dump all of the bridge domain details + // Use context to store already read information + // TODO Or just remove the getAllIds method and replace with a simple readAll + final vppBridgeDomainDetails bridgeDomainDetails = getVppApi().getBridgeDomainDetails(bId); + final String bName = bridgeDomainDetails.name; + allIds.add(new BridgeDomainKey(bName)); + } + + return allIds; + } + + @Override + public void merge(@Nonnull final Builder builder, @Nonnull final List readData) { + ((BridgeDomainsBuilder) builder).setBridgeDomain(readData); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vppstate/VersionCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vppstate/VersionCustomizer.java new file mode 100644 index 000000000..3e928176e --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vppstate/VersionCustomizer.java @@ -0,0 +1,59 @@ +/* + * 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.facade.v3po.vppstate; + +import io.fd.honeycomb.v3po.vpp.facade.Context; +import io.fd.honeycomb.v3po.vpp.facade.impl.util.VppApiCustomizer; +import io.fd.honeycomb.v3po.vpp.facade.spi.read.ChildVppReaderCustomizer; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppStateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.Version; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.VersionBuilder; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.vppjapi.vppVersion; + +public final class VersionCustomizer + extends VppApiCustomizer + implements ChildVppReaderCustomizer { + + public VersionCustomizer(@Nonnull final org.openvpp.vppjapi.vppApi vppApi) { + super(vppApi); + } + + @Override + public void merge(@Nonnull final Builder parentBuilder, @Nonnull final Version readValue) { + ((VppStateBuilder) parentBuilder).setVersion(readValue); + } + + @Nonnull + @Override + public VersionBuilder getBuilder(@Nonnull InstanceIdentifier id) { + return new VersionBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull InstanceIdentifier id, @Nonnull final VersionBuilder builder, + @Nonnull final Context context) { + final vppVersion vppVersion = getVppApi().getVppVersion(); + builder.setBranch(vppVersion.gitBranch); + builder.setName(vppVersion.programName); + builder.setBuildDate(vppVersion.buildDate); + builder.setBuildDirectory(vppVersion.buildDirectory); + } +} diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vpp/BridgeDomainCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vpp/BridgeDomainCustomizerTest.java new file mode 100644 index 000000000..059713544 --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vpp/BridgeDomainCustomizerTest.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.vpp.facade.v3po.vpp; + +import static io.fd.honeycomb.v3po.vpp.facade.v3po.vpp.BridgeDomainTestUtils.BD_NAME_TO_ID_ANSWER; +import static io.fd.honeycomb.v3po.vpp.facade.v3po.vpp.BridgeDomainTestUtils.bdIdentifierForName; +import static io.fd.honeycomb.v3po.vpp.facade.v3po.vpp.BridgeDomainTestUtils.bdNameToID; +import static io.fd.honeycomb.v3po.vpp.facade.v3po.vpp.BridgeDomainTestUtils.booleanToByte; +import static io.fd.honeycomb.v3po.vpp.facade.v3po.vpp.BridgeDomainTestUtils.intToBoolean; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.MockitoAnnotations.initMocks; + +import io.fd.honeycomb.v3po.vpp.facade.Context; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey; +import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; +import org.openvpp.vppjapi.vppApi; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(PowerMockRunner.class) +@SuppressStaticInitializationFor("org.openvpp.vppjapi.vppConn") +@PrepareForTest(vppApi.class) +public class BridgeDomainCustomizerTest { + + private static final int RESPONSE_NOT_READY = -77; + private static final byte ADD_OR_UPDATE_BD = (byte) 1; + private static final byte ZERO = 0; + private vppApi api; + + @Mock + private Context ctx; + + private BridgeDomainCustomizer customizer; + + @Before + public void setUp() throws Exception { + // TODO create base class for tests using vppApi + api = PowerMockito.mock(vppApi.class); + initMocks(this); + customizer = new BridgeDomainCustomizer(api); + + PowerMockito.doAnswer(BD_NAME_TO_ID_ANSWER).when(api).findOrAddBridgeDomainId(anyString()); + PowerMockito.doAnswer(BD_NAME_TO_ID_ANSWER).when(api).bridgeDomainIdFromName(anyString()); + PowerMockito.when(api.getRetval(anyInt(), anyInt())).thenReturn(RESPONSE_NOT_READY).thenReturn(0); + PowerMockito.doReturn(0).when(api).getRetval(anyInt(), anyInt()); + } + + private BridgeDomain generateBridgeDomain(final String bdName) { + final byte arpTerm = 0; + final byte flood = 1; + final byte forward = 0; + final byte learn = 1; + final byte uuf = 0; + return generateBridgeDomain(bdName, arpTerm, flood, forward, learn, uuf); + } + + private BridgeDomain generateBridgeDomain(final String bdName, final int arpTerm, final int flood, + final int forward, final int learn, final int uuf) { + return new BridgeDomainBuilder() + .setName(bdName) + .setArpTermination(intToBoolean(arpTerm)) + .setFlood(intToBoolean(flood)) + .setForward(intToBoolean(forward)) + .setLearn(intToBoolean(learn)) + .setUnknownUnicastFlood(intToBoolean(uuf)) + .build(); + } + + private final int verifyBridgeDomainAddOrUpdateWasInvoked(final BridgeDomain bd) { + final int bdn1Id = bdNameToID(bd.getName()); + final byte arpTerm = booleanToByte(bd.isArpTermination()); + final byte flood = booleanToByte(bd.isFlood()); + final byte forward = booleanToByte(bd.isForward()); + final byte learn = booleanToByte(bd.isLearn()); + final byte uuf = booleanToByte(bd.isUnknownUnicastFlood()); + return verify(api).bridgeDomainAddDel(bdn1Id, flood, forward, learn, uuf, arpTerm, ADD_OR_UPDATE_BD); + } + + private int verifyBridgeDomainAddOrUpdateWasNotInvoked(final BridgeDomain bd) { + final int bdn1Id = bdNameToID(bd.getName()); + final byte arpTerm = booleanToByte(bd.isArpTermination()); + final byte flood = booleanToByte(bd.isFlood()); + final byte forward = booleanToByte(bd.isForward()); + final byte learn = booleanToByte(bd.isLearn()); + final byte uuf = booleanToByte(bd.isUnknownUnicastFlood()); + return verify(api, never()).bridgeDomainAddDel(bdn1Id, flood, forward, learn, uuf, arpTerm, ADD_OR_UPDATE_BD); + } + + private int verifyBridgeDomainDeletedWasInvoked(final BridgeDomain bd) { + final int bdn1Id = bdNameToID(bd.getName()); + return verify(api).bridgeDomainAddDel(bdn1Id, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO); + } + + private int verifyBridgeDomainDeletedWasNotInvoked(final BridgeDomain bd) { + final int bdn1Id = bdNameToID(bd.getName()); + return verify(api, never()).bridgeDomainAddDel(bdn1Id, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO); + } + + @Test + public void testAddBridgeDomain() { + final String bdName = "bd1"; + final BridgeDomain bd = generateBridgeDomain("bd1"); + + customizer.writeCurrentAttributes(bdIdentifierForName(bdName), bd, ctx); + + verifyBridgeDomainAddOrUpdateWasInvoked(bd); + } + + @Test + public void testBridgeDomainNameCreateFailed() { + final String bdName = "bd1"; + final BridgeDomain bd = generateBridgeDomain("bd1"); + + // make vpp api fail to create id for our bd name + PowerMockito.doReturn(-1).when(api).findOrAddBridgeDomainId(bdName); + + try { + customizer.writeCurrentAttributes(bdIdentifierForName(bdName), bd, ctx); + } catch (IllegalStateException e) { + verifyBridgeDomainAddOrUpdateWasNotInvoked(bd); + return; + } + fail("IllegalStateException was expected"); + } + + @Test + public void testAddBridgeDomainFailed() { + // make any call to vpp fail + PowerMockito.doReturn(-1).when(api).getRetval(anyInt(), anyInt()); + + final String bdName = "bd1"; + final BridgeDomain bd = generateBridgeDomain(bdName); + + try { + customizer.writeCurrentAttributes(bdIdentifierForName(bdName), bd, ctx); + } catch (IllegalStateException e) { + verifyBridgeDomainAddOrUpdateWasInvoked(bd); + return; + } + fail("IllegalStateException was expected"); + } + + @Test + public void testDeleteBridgeDomain() { + final String bdName = "bd1"; + final BridgeDomain bd = generateBridgeDomain("bd1"); + + customizer.deleteCurrentAttributes(bdIdentifierForName(bdName), bd, ctx); + + verifyBridgeDomainDeletedWasInvoked(bd); + } + + @Test + public void testDeleteUnknownBridgeDomain() { + final String bdName = "bd1"; + final BridgeDomain bd = generateBridgeDomain("bd1"); + + // make vpp api not find our bd + PowerMockito.doReturn(-1).when(api).bridgeDomainIdFromName(bdName); + + try { + customizer.deleteCurrentAttributes(bdIdentifierForName(bdName), bd, ctx); + } catch (IllegalStateException e) { + verifyBridgeDomainDeletedWasNotInvoked(bd); + return; + } + fail("IllegalStateException was expected"); + } + + @Test + public void testDeleteBridgeDomainFailed() { + // make any call to vpp fail + PowerMockito.doReturn(-1).when(api).getRetval(anyInt(), anyInt()); + + final String bdName = "bd1"; + final BridgeDomain bd = generateBridgeDomain(bdName); + + try { + customizer.deleteCurrentAttributes(bdIdentifierForName(bdName), bd, ctx); + } catch (IllegalStateException e) { + verifyBridgeDomainDeletedWasInvoked(bd); + return; + } + fail("IllegalStateException was expected"); + } + + @Test + public void testUpdateBridgeDomain() throws Exception { + final String bdName = "bd1"; + final byte arpTermBefore = 1; + final byte floodBefore = 1; + final byte forwardBefore = 0; + final byte learnBefore = 1; + final byte uufBefore = 0; + + final BridgeDomain dataBefore = + generateBridgeDomain(bdName, arpTermBefore, floodBefore, forwardBefore, learnBefore, uufBefore); + final BridgeDomain dataAfter = + generateBridgeDomain(bdName, arpTermBefore ^ 1, floodBefore ^ 1, forwardBefore ^ 1, learnBefore ^ 1, + uufBefore ^ 1); + + final KeyedInstanceIdentifier id = bdIdentifierForName(bdName); + + customizer.updateCurrentAttributes(id, dataBefore, dataAfter, ctx); + + verifyBridgeDomainAddOrUpdateWasInvoked(dataAfter); + } + + @Test + public void testUpdateUnknownBridgeDomain() throws Exception { + final String bdName = "bd1"; + final BridgeDomain bd = generateBridgeDomain("bd1"); + + // make vpp api not find our bd + PowerMockito.doReturn(-1).when(api).bridgeDomainIdFromName(bdName); + + try { + customizer.updateCurrentAttributes(bdIdentifierForName(bdName), bd, bd, ctx); + } catch (IllegalStateException e) { + verifyBridgeDomainAddOrUpdateWasNotInvoked(bd); + return; + } + fail("IllegalStateException was expected"); + } + + @Test + public void testUpdateBridgeDomainFailed() { + // make any call to vpp fail + PowerMockito.doReturn(-1).when(api).getRetval(anyInt(), anyInt()); + + final String bdName = "bd1"; + final BridgeDomain bd = generateBridgeDomain(bdName); + + try { + customizer.updateCurrentAttributes(bdIdentifierForName(bdName), bd, bd, ctx); + } catch (IllegalStateException e) { + verifyBridgeDomainAddOrUpdateWasInvoked(bd); + return; + } + fail("IllegalStateException was expected"); + } + +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vpp/BridgeDomainTestUtils.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vpp/BridgeDomainTestUtils.java new file mode 100644 index 000000000..51a6b023e --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vpp/BridgeDomainTestUtils.java @@ -0,0 +1,64 @@ +/* + * 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.facade.v3po.vpp; + +import javax.annotation.Nullable; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; + +final class BridgeDomainTestUtils { + + private BridgeDomainTestUtils() { + throw new UnsupportedOperationException("Utility class cannot be instantiated."); + } + + public static byte booleanToByte(@Nullable final Boolean value) { + return value != null && value ? (byte) 1 : (byte) 0; + } + + @Nullable + public static Boolean intToBoolean(final int value) { + if (value == 0) { + return Boolean.FALSE; + } + if (value == 1) { + return Boolean.TRUE; + } + return null; + } + + public static int bdNameToID(String bName) { + return Integer.parseInt(((Character)bName.charAt(bName.length() - 1)).toString()); + } + + public static KeyedInstanceIdentifier bdIdentifierForName( + final String bdName) { + return InstanceIdentifier.create(BridgeDomains.class).child(BridgeDomain.class, new BridgeDomainKey(bdName)); + } + + public static final Answer BD_NAME_TO_ID_ANSWER = new Answer() { + @Override + public Integer answer(final InvocationOnMock invocationOnMock) throws Throwable { + return bdNameToID((String) invocationOnMock.getArguments()[0]); + } + }; +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vpp/VppTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vpp/VppTest.java new file mode 100644 index 000000000..bc5bda383 --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vpp/VppTest.java @@ -0,0 +1,174 @@ +/* + * 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.facade.v3po.vpp; + +import static io.fd.honeycomb.v3po.vpp.facade.v3po.vpp.BridgeDomainTestUtils.BD_NAME_TO_ID_ANSWER; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; + +import com.google.common.collect.Lists; +import io.fd.honeycomb.v3po.vpp.facade.impl.write.CompositeRootVppWriter; +import io.fd.honeycomb.v3po.vpp.facade.impl.write.util.DelegatingWriterRegistry; +import io.fd.honeycomb.v3po.vpp.facade.write.VppWriter; +import io.fd.honeycomb.v3po.vpp.facade.write.WriteContext; +import java.util.Collections; +import java.util.List; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomainsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainBuilder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.vppjapi.vppApi; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(PowerMockRunner.class) +@SuppressStaticInitializationFor("org.openvpp.vppjapi.vppConn") +@PrepareForTest(vppApi.class) +public class VppTest { + + private vppApi api; + private DelegatingWriterRegistry rootRegistry; + private CompositeRootVppWriter vppWriter; + private WriteContext ctx; + + final byte zero = (byte) 0; + final byte flood = (byte) 1; + final byte forward = (byte) 0; + final byte learn = (byte) 1; + final byte uuf = (byte) 0; + final byte arpTerm = (byte) 0; + final byte add = (byte) 1; + + @Before + public void setUp() throws Exception { + api = PowerMockito.mock(vppApi.class); + ctx = mock(WriteContext.class); + PowerMockito.doAnswer(BD_NAME_TO_ID_ANSWER).when(api).findOrAddBridgeDomainId(anyString()); + PowerMockito.doAnswer(BD_NAME_TO_ID_ANSWER).when(api).bridgeDomainIdFromName(anyString()); + PowerMockito.doReturn(1).when(api).getRetval(anyInt(), anyInt()); + vppWriter = VppUtils.getVppWriter(api); + rootRegistry = new DelegatingWriterRegistry( + Collections.>singletonList(vppWriter)); + } + + @Test + public void writeVpp() throws Exception { + rootRegistry.update( + InstanceIdentifier.create(Vpp.class), + null, + new VppBuilder().setBridgeDomains(getBridgeDomains("bdn1")).build(), + ctx); + + verify(api).bridgeDomainAddDel(1, flood, forward, learn, uuf, arpTerm, add); + + vppWriter.update(InstanceIdentifier.create(Vpp.class), + null, + new VppBuilder().setBridgeDomains(getBridgeDomains("bdn1")).build(), + ctx); + + verify(api, times(2)).bridgeDomainAddDel(1, flood, forward, learn, uuf, arpTerm, add); + } + + @Test + public void writeVppFromRoot() throws Exception { + final Vpp vpp = new VppBuilder().setBridgeDomains(getBridgeDomains("bdn1")).build(); + + rootRegistry.update(Collections., DataObject>emptyMap(), + Collections., DataObject>singletonMap(InstanceIdentifier.create(Vpp.class), + vpp), ctx); + + verify(api).bridgeDomainAddDel(1, flood, forward, learn, uuf, arpTerm, add); + } + + private BridgeDomains getBridgeDomains(String... name) { + final List bdmns = Lists.newArrayList(); + for (String s : name) { + bdmns.add(new BridgeDomainBuilder() + .setName(s) + .setArpTermination(false) + .setFlood(true) + .setForward(false) + .setLearn(true) + .build()); + } + return new BridgeDomainsBuilder() + .setBridgeDomain(bdmns) + .build(); + } + + @Test + public void deleteVpp() throws Exception { + rootRegistry.update( + InstanceIdentifier.create(Vpp.class), + new VppBuilder().setBridgeDomains(getBridgeDomains("bdn1")).build(), + null, + ctx); + + final byte zero = (byte) 0; + + verify(api).bridgeDomainAddDel(1, zero, zero, zero, zero, zero, zero); + } + + @Test + public void updateVppNoActualChange() throws Exception { + rootRegistry.update( + InstanceIdentifier.create(Vpp.class), + new VppBuilder().setBridgeDomains(getBridgeDomains("bdn1")).build(), + new VppBuilder().setBridgeDomains(getBridgeDomains("bdn1")).build(), + ctx); + + verifyZeroInteractions(api); + } + + @Test + public void writeUpdate() throws Exception { + final BridgeDomains domainsBefore = getBridgeDomains("bdn1"); + final BridgeDomain bdn1Before = domainsBefore.getBridgeDomain().get(0); + + final BridgeDomain bdn1After = new BridgeDomainBuilder(bdn1Before).setFlood(!bdn1Before.isFlood()).build(); + final BridgeDomains domainsAfter = new BridgeDomainsBuilder() + .setBridgeDomain(Collections.singletonList(bdn1After)) + .build(); + + rootRegistry.update( + InstanceIdentifier.create(Vpp.class), + new VppBuilder().setBridgeDomains(domainsBefore).build(), + new VppBuilder().setBridgeDomains(domainsAfter).build(), + ctx); + + final int bdn1Id = 1; + + // bdn1 is created with negated flood value + verify(api).bridgeDomainAddDel(bdn1Id, (byte) (flood ^ 1), forward, learn, uuf, arpTerm, add); + } + + // TODO test unkeyed list + // TODO test update of a child without dedicated writer +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vpp/VppUtils.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vpp/VppUtils.java new file mode 100644 index 000000000..ccf19c81c --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vpp/VppUtils.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.vpp.facade.v3po.vpp; + +import io.fd.honeycomb.v3po.vpp.facade.impl.util.VppRWUtils; +import io.fd.honeycomb.v3po.vpp.facade.impl.write.CompositeChildVppWriter; +import io.fd.honeycomb.v3po.vpp.facade.impl.write.CompositeListVppWriter; +import io.fd.honeycomb.v3po.vpp.facade.impl.write.CompositeRootVppWriter; +import io.fd.honeycomb.v3po.vpp.facade.impl.write.util.NoopWriterCustomizer; +import io.fd.honeycomb.v3po.vpp.facade.impl.write.util.ReflexiveChildWriterCustomizer; +import io.fd.honeycomb.v3po.vpp.facade.write.ChildVppWriter; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey; +import org.opendaylight.yangtools.yang.binding.ChildOf; +import org.openvpp.vppjapi.vppApi; + +final class VppUtils { + + public VppUtils() {} + + /** + * Create root Vpp writer with all its children wired + */ + static CompositeRootVppWriter getVppWriter(@Nonnull final vppApi vppApi) { + + final CompositeListVppWriter bridgeDomainWriter = new CompositeListVppWriter<>( + BridgeDomain.class, + new BridgeDomainCustomizer(vppApi)); + + final ChildVppWriter bridgeDomainsReader = new CompositeChildVppWriter<>( + BridgeDomains.class, + VppRWUtils.singletonChildWriterList(bridgeDomainWriter), + new ReflexiveChildWriterCustomizer()); + + final List>> childWriters = new ArrayList<>(); + childWriters.add(bridgeDomainsReader); + + return new CompositeRootVppWriter<>( + Vpp.class, + childWriters, + new NoopWriterCustomizer()); + } +} diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vppstate/VppStateTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vppstate/VppStateTest.java new file mode 100644 index 000000000..059c98f56 --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vppstate/VppStateTest.java @@ -0,0 +1,259 @@ +/* + * 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.facade.v3po.vppstate; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; + +import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; +import com.google.common.collect.Multimap; +import io.fd.honeycomb.v3po.vpp.facade.impl.read.CompositeListVppReader; +import io.fd.honeycomb.v3po.vpp.facade.impl.read.CompositeRootVppReader; +import io.fd.honeycomb.v3po.vpp.facade.impl.read.util.DelegatingReaderRegistry; +import io.fd.honeycomb.v3po.vpp.facade.read.ReadContext; +import io.fd.honeycomb.v3po.vpp.facade.read.VppReader; +import java.util.Collections; +import java.util.List; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Matchers; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppStateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomains; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.Version; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.VersionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.L2Fib; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.L2FibKey; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.vppjapi.vppApi; +import org.openvpp.vppjapi.vppBridgeDomainDetails; +import org.openvpp.vppjapi.vppBridgeDomainInterfaceDetails; +import org.openvpp.vppjapi.vppL2Fib; +import org.openvpp.vppjapi.vppVersion; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(PowerMockRunner.class) +@SuppressStaticInitializationFor("org.openvpp.vppjapi.vppConn") +@PrepareForTest(vppApi.class) +public class VppStateTest { + + public static final vppVersion VERSION = new vppVersion("test", "1", "2", "33"); + + private vppApi api; + private CompositeRootVppReader vppStateReader; + private DelegatingReaderRegistry readerRegistry; + private vppBridgeDomainDetails bdDetails; + private vppBridgeDomainDetails bdDetails2; + private ReadContext ctx; + + @Before + public void setUp() throws Exception { + api = PowerMockito.mock(vppApi.class); + + ctx = mock(ReadContext.class); + + bdDetails = new vppBridgeDomainDetails(); + setIfcs(bdDetails); + setBaseAttrs(bdDetails, "bdn1", 1); + + bdDetails2 = new vppBridgeDomainDetails(); + setIfcs(bdDetails2); + setBaseAttrs(bdDetails2, "bdn2", 2); + + final vppL2Fib[] l2Fibs = getL2Fibs(); + PowerMockito.doReturn(l2Fibs).when(api).l2FibTableDump(Matchers.anyInt()); + PowerMockito.doAnswer(new Answer() { + + @Override + public vppBridgeDomainDetails answer(final InvocationOnMock invocationOnMock) throws Throwable { + final Integer idx = (Integer) invocationOnMock.getArguments()[0]; + switch (idx) { + case 1 : return bdDetails; + case 2 : return bdDetails2; + default: return null; + } + } + }).when(api).getBridgeDomainDetails(Matchers.anyInt()); + + PowerMockito.doAnswer(new Answer() { + @Override + public Object answer(final InvocationOnMock invocationOnMock) throws Throwable { + final String name = (String) invocationOnMock.getArguments()[0]; + switch (name) { + case "bdn1" : return 1; + case "bdn2" : return 2; + default: return null; + } + } + }).when(api).bridgeDomainIdFromName(anyString()); + PowerMockito.doReturn(new int[] {1, 2}).when(api).bridgeDomainDump(Matchers.anyInt()); + PowerMockito.doReturn(VERSION).when(api).getVppVersion(); + vppStateReader = VppStateUtils.getVppStateReader(api); + readerRegistry = new DelegatingReaderRegistry(Collections.>singletonList(vppStateReader)); + } + + private vppL2Fib[] getL2Fibs() { + return new vppL2Fib[] { + new vppL2Fib(new byte[]{1,2,3,4,5,6}, true, "ifc1", true, true), + new vppL2Fib(new byte[]{2,2,3,4,5,6}, true, "ifc2", true, true), + }; + } + + private void setIfcs(final vppBridgeDomainDetails bdDetails) { + final vppBridgeDomainInterfaceDetails ifcDetails = new vppBridgeDomainInterfaceDetails(); + ifcDetails.interfaceName = "ifc"; + ifcDetails.splitHorizonGroup = 2; + bdDetails.interfaces = new vppBridgeDomainInterfaceDetails[] {ifcDetails}; + } + + private void setBaseAttrs(final vppBridgeDomainDetails bdDetails, final String bdn, final int i) { + bdDetails.name = bdn; + bdDetails.arpTerm = true; + bdDetails.bdId = i; + bdDetails.bviInterfaceName = "ifc"; + bdDetails.flood = true; + bdDetails.forward = true; + bdDetails.learn = true; + bdDetails.uuFlood = true; + } + + @Test + public void testReadAll() throws Exception { + final Multimap, ? extends DataObject> dataObjects = readerRegistry.readAll(ctx); + assertEquals(dataObjects.size(), 1); + final DataObject dataObject = Iterables.getOnlyElement(dataObjects.get(Iterables.getOnlyElement(dataObjects.keySet()))); + assertTrue(dataObject instanceof VppState); + assertVersion((VppState) dataObject); + assertEquals(2, ((VppState) dataObject).getBridgeDomains().getBridgeDomain().size()); + } + + private void assertVersion(final VppState dataObject) { + assertEquals( + new VersionBuilder() + .setName("test") + .setBuildDirectory("1") + .setBranch("2") + .setBuildDate("33") + .build(), + dataObject.getVersion()); + } + + @Test + public void testReadSpecific() throws Exception { + final Optional read = readerRegistry.read(InstanceIdentifier.create(VppState.class), ctx); + assertTrue(read.isPresent()); + assertVersion((VppState) read.get()); + } + + @Test + public void testReadBridgeDomains() throws Exception { + VppState readRoot = (VppState) readerRegistry.read(InstanceIdentifier.create(VppState.class), ctx).get(); + + Optional read = + readerRegistry.read(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class), ctx); + assertTrue(read.isPresent()); + assertEquals(readRoot.getBridgeDomains(), read.get()); + } + + /** + * L2fib does not have a dedicated reader, relying on auto filtering + */ + @Test + public void testReadL2Fib() throws Exception { + // Deep child without a dedicated reader with specific l2fib key + Optional read = + readerRegistry.read(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child( + BridgeDomain.class, new BridgeDomainKey("bdn1")) + .child(L2Fib.class, new L2FibKey(new PhysAddress("01:02:03:04:05:06"))), ctx); + assertTrue(read.isPresent()); + + // non existing l2fib + read = + readerRegistry.read(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child( + BridgeDomain.class, new BridgeDomainKey("bdn1")) + .child(L2Fib.class, new L2FibKey(new PhysAddress("FF:FF:FF:04:05:06"))), ctx); + assertFalse(read.isPresent()); + } + + @Test + public void testReadBridgeDomainAll() throws Exception { + VppState readRoot = (VppState) readerRegistry.read(InstanceIdentifier.create(VppState.class), ctx).get(); + + final CompositeListVppReader bridgeDomainReader = + VppStateUtils.getBridgeDomainReader(api); + + final List read = + bridgeDomainReader.readList(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child( + BridgeDomain.class), ctx); + + assertEquals(readRoot.getBridgeDomains().getBridgeDomain(), read); + } + + @Test + public void testReadBridgeDomain() throws Exception { + VppState readRoot = (VppState) readerRegistry.read(InstanceIdentifier.create(VppState.class), ctx).get(); + + final Optional read = + readerRegistry.read(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child( + BridgeDomain.class, new BridgeDomainKey("bdn1")), ctx); + + assertTrue(read.isPresent()); + assertEquals(Iterables.find(readRoot.getBridgeDomains().getBridgeDomain(), new Predicate() { + @Override + public boolean apply(final BridgeDomain input) { + return input.getKey().getName().equals("bdn1"); + } + }), read.get()); + } + + // FIXME + @Ignore("Bridge domain customizer does not check whether the bd exists or not and fails with NPE, add it there") + @Test + public void testReadBridgeDomainNotExisting() throws Exception { + final Optional read = + readerRegistry.read(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child( + BridgeDomain.class, new BridgeDomainKey("NOT EXISTING")), ctx); + assertFalse(read.isPresent()); + } + + @Test + public void testReadVersion() throws Exception { + VppState readRoot = (VppState) readerRegistry.read(InstanceIdentifier.create(VppState.class), ctx).get(); + + Optional read = + readerRegistry.read(InstanceIdentifier.create(VppState.class).child(Version.class), ctx); + assertTrue(read.isPresent()); + assertEquals(readRoot.getVersion(), read.get()); + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vppstate/VppStateUtils.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vppstate/VppStateUtils.java new file mode 100644 index 000000000..7d5441769 --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/vpp/facade/v3po/vppstate/VppStateUtils.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.vpp.facade.v3po.vppstate; + +import io.fd.honeycomb.v3po.vpp.facade.impl.read.CompositeChildVppReader; +import io.fd.honeycomb.v3po.vpp.facade.impl.read.CompositeListVppReader; +import io.fd.honeycomb.v3po.vpp.facade.impl.read.CompositeRootVppReader; +import io.fd.honeycomb.v3po.vpp.facade.impl.read.util.ReflexiveChildReaderCustomizer; +import io.fd.honeycomb.v3po.vpp.facade.impl.read.util.ReflexiveRootReaderCustomizer; +import io.fd.honeycomb.v3po.vpp.facade.impl.util.VppRWUtils; +import io.fd.honeycomb.v3po.vpp.facade.read.ChildVppReader; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppStateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomains; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomainsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.Version; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainKey; +import org.opendaylight.yangtools.yang.binding.ChildOf; +import org.openvpp.vppjapi.vppApi; + +final class VppStateUtils { + + public VppStateUtils() {} + + /** + * Create root VppState reader with all its children wired + */ + static CompositeRootVppReader getVppStateReader(@Nonnull final vppApi vppApi) { + + final ChildVppReader versionReader = new CompositeChildVppReader<>( + Version.class, new VersionCustomizer(vppApi)); + + final CompositeListVppReader bridgeDomainReader = + getBridgeDomainReader(vppApi); + + final ChildVppReader bridgeDomainsReader = new CompositeChildVppReader<>( + BridgeDomains.class, + VppRWUtils.singletonChildReaderList(bridgeDomainReader), + new ReflexiveChildReaderCustomizer<>(BridgeDomainsBuilder.class)); + + final List>> childVppReaders = new ArrayList<>(); + childVppReaders.add(versionReader); + childVppReaders.add(bridgeDomainsReader); + + return new CompositeRootVppReader<>( + VppState.class, + childVppReaders, + VppRWUtils.emptyAugReaderList(), + new ReflexiveRootReaderCustomizer<>(VppStateBuilder.class)); + } + + static CompositeListVppReader getBridgeDomainReader( + final @Nonnull vppApi vppApi) { + return new CompositeListVppReader<>( + BridgeDomain.class, + new BridgeDomainCustomizer(vppApi)); + } +} diff --git a/v3po/vpp-facade-api/pom.xml b/v3po/vpp-facade-api/pom.xml new file mode 100644 index 000000000..0406f1e80 --- /dev/null +++ b/v3po/vpp-facade-api/pom.xml @@ -0,0 +1,73 @@ + + + + + io.fd.honeycomb.common + api-parent + 1.0.0-SNAPSHOT + ../../common/api-parent + + + 4.0.0 + io.fd.honeycomb.v3po + vpp-facade-api + 1.0.0-SNAPSHOT + bundle + + + + + org.opendaylight.mdsal + mdsal-artifacts + 2.0.0-Beryllium + pom + import + + + + + + + com.google.guava + guava + + + org.opendaylight.mdsal + mdsal-binding-api + + + + + ${project.groupId} + v3po-api + ${project.version} + test + + + junit + junit + test + + + org.mockito + mockito-all + test + + + + + diff --git a/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/Context.java b/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/Context.java new file mode 100644 index 000000000..16808db1f --- /dev/null +++ b/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/Context.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.vpp.facade; + +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 Context implements AutoCloseable { + + protected final HashMap map; + + public Context() { + 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/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/SubtreeManager.java b/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/SubtreeManager.java new file mode 100644 index 000000000..28eee203b --- /dev/null +++ b/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/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.vpp.facade; + +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 Specific DataObject derived type, that is managed by this manager + */ +@Beta +public interface SubtreeManager { + + /** + * Gets the type of node managed by this reader + * + * @return Class object for node managed by this reader + */ + @Nonnull + InstanceIdentifier getManagedDataObjectType(); +} diff --git a/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/VppApiInvocationException.java b/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/VppApiInvocationException.java new file mode 100644 index 000000000..ac1d7f7db --- /dev/null +++ b/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/VppApiInvocationException.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.vpp.facade; + +import com.google.common.annotations.Beta; +import com.google.common.base.Preconditions; +import javax.annotation.Nonnull; + +/** + * Thrown when Vpp jAPI method invocation failed. + */ +@Beta +public class VppApiInvocationException extends VppException { + private final String methodName; + private final int ctxId; + private final int errorCode; + + /** + * Constructs an VppApiInvocationFailedException with the specified api method name and error code. + * + * @param methodName method name that failed to invoke + * @param ctxId api request context identifier + * @param errorCode negative error code value associated with this failure + * @throws NullPointerException if apiMethodName is null + * @throws IllegalArgumentException if errorCode is nonnegative + */ + public VppApiInvocationException(@Nonnull final String methodName, final int ctxId, final int errorCode) { + super(String.format("vppApi.%s failed with error code: %d (ctxId=%d) ", methodName, errorCode, ctxId)); + this.methodName = Preconditions.checkNotNull(methodName, "apiMethodName is null!"); + this.ctxId = ctxId; + Preconditions.checkArgument(errorCode < 0); + this.errorCode = errorCode; + } + + /** + * Returns method name that failed to invoke. + * + * @return method name + */ + public String getMethodName() { + return methodName; + } + + /** + * Returns api request context identifier. + * + * @return value of context identifier + */ + public int getCtxId() { + return ctxId; + } + + /** + * Returns the error code associated with this failure. + * + * @return a negative integer error code + */ + public int getErrorCode() { + return errorCode; + } +} + diff --git a/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/VppException.java b/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/VppException.java new file mode 100644 index 000000000..ff6101bb8 --- /dev/null +++ b/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/VppException.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.vpp.facade; + +import com.google.common.annotations.Beta; + +/** + * Base exception for Vpp translation layer + */ +@Beta +public class VppException extends Exception { + + public VppException(final String s) { + super(s); + } + + public VppException(final String s, final Throwable cause) { + super(s, cause); + } + + public VppException(final Throwable cause) { + super(cause); + } +} diff --git a/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/read/ChildVppReader.java b/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/read/ChildVppReader.java new file mode 100644 index 000000000..1608db4b2 --- /dev/null +++ b/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/read/ChildVppReader.java @@ -0,0 +1,50 @@ +/* + * 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.facade.read; + +import com.google.common.annotations.Beta; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Child VPP reader allowing its parent to pass the builder object + * + * @param Specific DataObject derived type, that is handled by this reader + */ +@Beta +public interface ChildVppReader extends VppReader { + + /** + * Reads subtree starting from node managed by this reader and place the subtree within parent builder object if the + * data exists. + * + * @param id Unique identifier pointing to the node managed by this reader. Useful when necessary to + * determine the exact position within more complex subtrees. + * @param parentBuilder Builder of parent DataObject. Objects read on this level (if any) must be placed into the + * parent builder. + * @param ctx Read context + * + * @throws ReadFailedException if read was unsuccessful + */ + void read(@Nonnull final InstanceIdentifier id, + @Nonnull final Builder parentBuilder, + @Nonnull final ReadContext ctx) throws ReadFailedException; + +} + diff --git a/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/read/ListVppReader.java b/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/read/ListVppReader.java new file mode 100644 index 000000000..950014574 --- /dev/null +++ b/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/read/ListVppReader.java @@ -0,0 +1,47 @@ +/* + * 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.facade.read; + +import com.google.common.annotations.Beta; +import java.util.List; +import javax.annotation.Nonnull; +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 VPP reader, allowing read of all the elements + * + * @param Specific DataObject derived type, that is handled by this reader + */ +@Beta +public interface ListVppReader, K extends Identifier> extends VppReader { + + /** + * 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 readList(@Nonnull final InstanceIdentifier id, + @Nonnull final ReadContext ctx) throws ReadFailedException; +} diff --git a/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/read/ReadContext.java b/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/read/ReadContext.java new file mode 100644 index 000000000..527888ab1 --- /dev/null +++ b/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/read/ReadContext.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.vpp.facade.read; + +import io.fd.honeycomb.v3po.vpp.facade.Context; +import javax.annotation.Nonnull; + +/** + * Read Context + */ +public interface ReadContext extends AutoCloseable { + + /** + * Get key value storage for customizers + * + * @return Context for customizers + */ + @Nonnull + Context getContext(); + + @Override + void close(); +} diff --git a/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/read/ReadFailedException.java b/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/read/ReadFailedException.java new file mode 100644 index 000000000..3e87b925b --- /dev/null +++ b/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/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.vpp.facade.read; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.honeycomb.v3po.vpp.facade.VppException; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Thrown when Vpp reader or customizer is not able to read data for the given id. + */ +public class ReadFailedException extends VppException { + + 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/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/read/ReaderRegistry.java b/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/read/ReaderRegistry.java new file mode 100644 index 000000000..2bd51254f --- /dev/null +++ b/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/read/ReaderRegistry.java @@ -0,0 +1,43 @@ +/* + * 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.facade.read; + +import com.google.common.annotations.Beta; +import com.google.common.collect.Multimap; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Simple delegating reader suitable as a holder for all other root readers, providing readAll feature. + */ +@Beta +public interface ReaderRegistry extends VppReader { + + /** + * Performs read on all registered root readers and merges the results into a Multimap. Keys represent identifiers + * for root DataObjects from the data tree modeled by YANG. + * + * @param ctx Read context + * + * @return multimap that preserves deterministic iteration order across non-distinct key values + * @throws ReadFailedException if read was unsuccessful + */ + @Nonnull + Multimap, ? extends DataObject> readAll(@Nonnull final ReadContext ctx) + throws ReadFailedException; +} diff --git a/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/read/VppReader.java b/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/read/VppReader.java new file mode 100644 index 000000000..6eea594b4 --- /dev/null +++ b/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/read/VppReader.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.facade.read; + +import com.google.common.annotations.Beta; +import com.google.common.base.Optional; +import io.fd.honeycomb.v3po.vpp.facade.SubtreeManager; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Base VPP reader, responsible for translation between DataObjects and VPP APIs + * + * @param Specific DataObject derived type, that is handled by this reader + */ +@Beta +public interface VppReader extends SubtreeManager { + + // TODO make async + + /** + * Reads from VPP data identified by id + * + * @param id unique identifier of subtree to be read. The subtree must contain managed data object type. For + * identifiers pointing below node managed by this reader, it's reader's responsibility to filter out the + * right node or to delegate the read to a child reader. + * @param ctx Read context + * + * @return List of DataObjects identified by id. If the ID points to a single node, it will be wrapped in a list + * @throws ReadFailedException if read was unsuccessful + */ + @Nonnull + Optional read(@Nonnull final InstanceIdentifier id, + @Nonnull ReadContext ctx) throws ReadFailedException; + +} diff --git a/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/write/ChildVppWriter.java b/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/write/ChildVppWriter.java new file mode 100644 index 000000000..017f5d9aa --- /dev/null +++ b/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/write/ChildVppWriter.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.facade.write; + +import com.google.common.annotations.Beta; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Child VPP writer allowing its parent to pass the builder object + * + * @param Specific DataObject derived type, that is handled by this writer + */ +@Beta +public interface ChildVppWriter extends VppWriter { + + /** + * Extract data object managed by this writer from parent data and perform write. + * + * @param parentId Id of parent node + * @param parentDataAfter Parent data from modification to extract data object from + * @param ctx Write context for current modification + */ + void writeChild(@Nonnull final InstanceIdentifier parentId, + @Nonnull final DataObject parentDataAfter, + @Nonnull final WriteContext ctx); + + /** + * Extract data object managed by this writer(if necessary) from parent data and perform delete. + * + * @param parentId Id of parent node + * @param parentDataBefore Parent data before modification to extract data object from + * @param ctx Write context for current modification + */ + void deleteChild(@Nonnull final InstanceIdentifier parentId, + @Nonnull final DataObject parentDataBefore, + @Nonnull final WriteContext ctx); + + /** + * Extract data object managed by this writer(if necessary) from parent data and perform delete. + * + * @param parentId Id of parent node + * @param parentDataBefore Parent data before modification to extract data object from + * @param parentDataAfter Parent data from modification to extract data object from + * @param ctx Write context for current modification + */ + void updateChild(@Nonnull final InstanceIdentifier parentId, + @Nonnull final DataObject parentDataBefore, + @Nonnull final DataObject parentDataAfter, + @Nonnull final WriteContext ctx); +} diff --git a/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/write/VppWriter.java b/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/write/VppWriter.java new file mode 100644 index 000000000..83f600f5b --- /dev/null +++ b/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/write/VppWriter.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.vpp.facade.write; + +import com.google.common.annotations.Beta; +import io.fd.honeycomb.v3po.vpp.facade.SubtreeManager; +import io.fd.honeycomb.v3po.vpp.facade.VppException; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Base VPP writer, responsible for translation between DataObjects and VPP APIs. Handling all update operations(create, + * update, delete) + * + * @param Specific DataObject derived type, that is handled by this writer + */ +@Beta +public interface VppWriter extends SubtreeManager { + + /** + * Handle update operation. U from CRUD. + * + * @param id Identifier(from root) of data being written + * @param dataBefore Old data + * @param dataAfter New, updated data + * @param ctx Write context enabling writer to get information about candidate data as well as current data + * @throws VppException if update failed + */ + void update(@Nonnull final InstanceIdentifier id, + @Nullable final DataObject dataBefore, + @Nullable final DataObject dataAfter, + @Nonnull final WriteContext ctx) throws VppException; +} diff --git a/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/write/WriteContext.java b/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/write/WriteContext.java new file mode 100644 index 000000000..ffc9f20f7 --- /dev/null +++ b/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/write/WriteContext.java @@ -0,0 +1,60 @@ +/* + * 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.facade.write; + +import com.google.common.annotations.Beta; +import com.google.common.base.Optional; +import io.fd.honeycomb.v3po.vpp.facade.Context; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Context providing information about current state of DataTree to writers + */ +@Beta +public interface WriteContext extends AutoCloseable { + + /** + * Read any data object before current modification was applied + * + * @param currentId Id of an object to read + * + * @return Data before the modification was applied + */ + Optional readBefore(@Nonnull final InstanceIdentifier currentId); + + /** + * Read any data object from current modification + * + * @param currentId Id of an object to read + * + * @return Data from the modification + */ + Optional readAfter(@Nonnull final InstanceIdentifier currentId); + + /** + * Get key value storage for customizers + * + * @return Context for customizers + */ + @Nonnull + Context getContext(); + + @Override + void close(); +} diff --git a/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/write/WriterRegistry.java b/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/write/WriterRegistry.java new file mode 100644 index 000000000..0d3c17451 --- /dev/null +++ b/v3po/vpp-facade-api/src/main/java/io/fd/honeycomb/v3po/vpp/facade/write/WriterRegistry.java @@ -0,0 +1,135 @@ +/* + * 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.facade.write; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.annotations.Beta; +import com.google.common.collect.ImmutableList; +import io.fd.honeycomb.v3po.vpp.facade.VppException; +import java.util.List; +import java.util.Map; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Special {@link VppWriter} capable of performing bulk updates + */ +@Beta +public interface WriterRegistry extends VppWriter { + + /** + * Performs bulk update + * + * @throws BulkUpdateException in case bulk update fails + * @throws VppException in case some other error occurs while processing update request + */ + void update(@Nonnull final Map, DataObject> dataBefore, + @Nonnull final Map, DataObject> dataAfter, + @Nonnull final WriteContext ctx) throws VppException; + + /** + * Thrown when bulk update failed. + */ + @Beta + class BulkUpdateException extends VppException { + + private final Reverter reverter; + private final InstanceIdentifier failedId; // TODO change to VppDataModification + + /** + * Constructs an BulkUpdateException. + * + * @param failedId instance identifier of the data object that caused bulk update to fail. + * @param cause the cause of bulk update failure + */ + public BulkUpdateException(@Nonnull final InstanceIdentifier failedId, @Nonnull final Reverter reverter, + final Throwable cause) { + super("Bulk update failed at " + failedId, cause); + this.failedId = checkNotNull(failedId, "failedId should not be null"); + this.reverter = checkNotNull(reverter, "reverter should not be null"); + } + + /** + * Reverts changes that were successfully applied during bulk update before failure occurred. + * + * @throws Reverter.RevertFailedException if revert fails + */ + public void revertChanges() throws Reverter.RevertFailedException { + reverter.revert(); + } + + /** + * Returns instance identifier of the data object that caused bulk update to fail. + * + * @return data object's instance identifier + */ + @Nonnull + public InstanceIdentifier getFailedId() { + return failedId; + } + } + + /** + * Abstraction over revert mechanism in cast of a bulk update failure + */ + @Beta + interface Reverter { + + /** + * Reverts changes that were successfully applied during bulk update before failure occurred. Changes are + * reverted in reverse order they were applied. + * + * @throws RevertFailedException if not all of applied changes were successfully reverted + */ + void revert() throws RevertFailedException; + + /** + * Thrown when some of the changes applied during bulk update were not reverted. + */ + @Beta + class RevertFailedException extends VppException { + + // TODO change to list of VppDataModifications to make debugging easier + private final List> notRevertedChanges; + + /** + * Constructs an RevertFailedException with the list of changes that were not reverted. + * + * @param notRevertedChanges list of changes that were not reverted + * @param cause the cause of revert failure + */ + public RevertFailedException(@Nonnull final List> notRevertedChanges, + final Throwable cause) { + super(cause); + checkNotNull(notRevertedChanges, "notRevertedChanges should not be null"); + this.notRevertedChanges = ImmutableList.copyOf(notRevertedChanges); + } + + /** + * Returns the list of changes that were not reverted. + * + * @return list of changes that were not reverted + */ + @Nonnull + public List> getNotRevertedChanges() { + return notRevertedChanges; + } + } + } +} \ No newline at end of file diff --git a/v3po/vpp-facade-api/src/test/java/io/fd/honeycomb/v3po/vpp/facade/ReadFailedExceptionTest.java b/v3po/vpp-facade-api/src/test/java/io/fd/honeycomb/v3po/vpp/facade/ReadFailedExceptionTest.java new file mode 100644 index 000000000..594168df2 --- /dev/null +++ b/v3po/vpp-facade-api/src/test/java/io/fd/honeycomb/v3po/vpp/facade/ReadFailedExceptionTest.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.facade; + +import io.fd.honeycomb.v3po.vpp.facade.read.ReadFailedException; +import org.junit.Assert; +import org.junit.Test; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.Interface; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class ReadFailedExceptionTest { + + @Test + public void testInstantiation() { + final InstanceIdentifier id = InstanceIdentifier.create(BridgeDomain.class); + ReadFailedException e = new ReadFailedException(id); + Assert.assertEquals(id, e.getFailedId()); + Assert.assertNull(e.getCause()); + Assert.assertTrue(e.getMessage().contains(id.toString())); + } + + @Test + public void testInstantiationWithCause() { + final InstanceIdentifier id = InstanceIdentifier.create(Interface.class); + final RuntimeException cause = new RuntimeException(); + ReadFailedException e = new ReadFailedException(id, cause); + Assert.assertEquals(id, e.getFailedId()); + Assert.assertEquals(cause, e.getCause()); + Assert.assertTrue(e.getMessage().contains(id.toString())); + } + + @Test(expected = NullPointerException.class) + public void testInstantiationFailed() { + new ReadFailedException(null); + } +} \ No newline at end of file diff --git a/v3po/vpp-facade-api/src/test/java/io/fd/honeycomb/v3po/vpp/facade/VppApiInvocationExceptionTest.java b/v3po/vpp-facade-api/src/test/java/io/fd/honeycomb/v3po/vpp/facade/VppApiInvocationExceptionTest.java new file mode 100644 index 000000000..a3a37c192 --- /dev/null +++ b/v3po/vpp-facade-api/src/test/java/io/fd/honeycomb/v3po/vpp/facade/VppApiInvocationExceptionTest.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.vpp.facade; + +import java.util.Random; +import org.junit.Assert; +import org.junit.Test; + +public class VppApiInvocationExceptionTest { + + @Test + public void testInstantiation() { + final String apiMethodName = "methodName"; + final int ctxId = 1; + final int code = -1; + VppApiInvocationException e = new VppApiInvocationException(apiMethodName, ctxId, code); + Assert.assertEquals(apiMethodName, e.getMethodName()); + Assert.assertEquals(ctxId, e.getCtxId()); + Assert.assertEquals(code, e.getErrorCode()); + Assert.assertTrue(e.getMessage().contains(apiMethodName)); + Assert.assertTrue(e.getMessage().contains(String.valueOf(code))); + Assert.assertTrue(e.getMessage().contains(String.valueOf(ctxId))); + } + + @Test(expected = IllegalArgumentException.class) + public void testInstantiationFailed() { + final int code = new Random().nextInt(Integer.MAX_VALUE); + VppApiInvocationException e = new VppApiInvocationException("apiMethodName", 1, code); + } +} diff --git a/v3po/vpp-facade-impl/pom.xml b/v3po/vpp-facade-impl/pom.xml new file mode 100644 index 000000000..fff69c2b7 --- /dev/null +++ b/v3po/vpp-facade-impl/pom.xml @@ -0,0 +1,88 @@ + + + + + io.fd.honeycomb.common + api-parent + 1.0.0-SNAPSHOT + ../../common/api-parent + + + 4.0.0 + io.fd.honeycomb.v3po + vpp-facade-impl + 1.0.0-SNAPSHOT + bundle + + + + ${project.groupId} + vpp-facade-api + ${project.version} + + + ${project.groupId} + vpp-facade-spi + ${project.version} + + + ${project.groupId} + vpp-facade-utils + ${project.version} + + + + + ${project.groupId} + v3po-api + ${project.version} + test + + + junit + junit + test + + + org.mockito + mockito-all + test + + + + + + + maven-jar-plugin + + + org.apache.felix + maven-bundle-plugin + true + + + ${project.groupId}.${project.artifactId} + + io.fd.honeycomb.v3po.vpp.facade.impl.* + + + + + + + + diff --git a/v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/AbstractCompositeVppReader.java b/v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/AbstractCompositeVppReader.java new file mode 100644 index 000000000..2856937ba --- /dev/null +++ b/v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/AbstractCompositeVppReader.java @@ -0,0 +1,232 @@ +/* + * 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.facade.impl.read; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.annotations.Beta; +import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; +import io.fd.honeycomb.v3po.vpp.facade.impl.util.ReflectionUtils; +import io.fd.honeycomb.v3po.vpp.facade.impl.util.VppRWUtils; +import io.fd.honeycomb.v3po.vpp.facade.read.ChildVppReader; +import io.fd.honeycomb.v3po.vpp.facade.read.ReadContext; +import io.fd.honeycomb.v3po.vpp.facade.read.ReadFailedException; +import io.fd.honeycomb.v3po.vpp.facade.read.VppReader; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.Augmentation; +import org.opendaylight.yangtools.yang.binding.ChildOf; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.Identifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Beta +abstract class AbstractCompositeVppReader> implements VppReader { + + private static final Logger LOG = LoggerFactory.getLogger(AbstractCompositeVppReader.class); + + private final Map, ChildVppReader>> childReaders; + private final Map, ChildVppReader>> augReaders; + private final InstanceIdentifier instanceIdentifier; + + AbstractCompositeVppReader(final Class managedDataObjectType, + final List>> childReaders, + final List>> augReaders) { + this.childReaders = VppRWUtils.uniqueLinkedIndex(childReaders, VppRWUtils.MANAGER_CLASS_FUNCTION); + this.augReaders = VppRWUtils.uniqueLinkedIndex(augReaders, VppRWUtils.MANAGER_CLASS_AUG_FUNCTION); + this.instanceIdentifier = InstanceIdentifier.create(managedDataObjectType); + } + + @Nonnull + @Override + public final InstanceIdentifier getManagedDataObjectType() { + return instanceIdentifier; + } + + /** + * @param id {@link InstanceIdentifier} pointing to current node. In case of keyed list, key must be present. + * + */ + protected Optional readCurrent(final InstanceIdentifier id, + @Nonnull final ReadContext ctx) throws ReadFailedException { + LOG.debug("{}: Reading current: {}", this, id); + final B builder = getBuilder(id); + // Cache empty value to determine if anything has changed later TODO cache in a field + final D emptyValue = builder.build(); + + LOG.trace("{}: Reading current attributes", this); + readCurrentAttributes(id, builder, ctx); + + // TODO expect exceptions from reader + for (ChildVppReader> child : childReaders.values()) { + LOG.debug("{}: Reading child from: {}", this, child); + child.read(id, builder, ctx); + } + + for (ChildVppReader> child : augReaders.values()) { + LOG.debug("{}: Reading augment from: {}", this, child); + child.read(id, builder, ctx); + } + + // Need to check whether anything was filled in to determine if data is present or not. + final D built = builder.build(); + final Optional read = built.equals(emptyValue) + ? Optional.absent() + : Optional.of(built); + + LOG.debug("{}: Current node read successfully. Result: {}", this, read); + return read; + } + + @Nonnull + @Override + @SuppressWarnings("unchecked") + public Optional read(@Nonnull final InstanceIdentifier id, + @Nonnull final ReadContext ctx) + throws ReadFailedException { + LOG.trace("{}: Reading : {}", this, id); + if (id.getTargetType().equals(getManagedDataObjectType().getTargetType())) { + return readCurrent((InstanceIdentifier) id, ctx); + } else { + return readSubtree(id, ctx); + } + } + + private Optional readSubtree(final InstanceIdentifier id, + @Nonnull final ReadContext ctx) + throws ReadFailedException { + LOG.debug("{}: Reading subtree: {}", this, id); + final Class next = VppRWUtils.getNextId(id, getManagedDataObjectType()).getType(); + final ChildVppReader> vppReader = childReaders.get(next); + + if (vppReader != null) { + LOG.debug("{}: Reading subtree: {} from: {}", this, id, vppReader); + return vppReader.read(id, ctx); + } else { + LOG.debug("{}: Dedicated subtree reader missing for: {}. Reading current and filtering", this, next); + // If there's no dedicated reader, use read current + final InstanceIdentifier currentId = VppRWUtils.cutId(id, getManagedDataObjectType()); + final Optional current = readCurrent(currentId, ctx); + // then perform post-reading filtering (return only requested sub-node) + final Optional readSubtree = current.isPresent() + ? filterSubtree(current.get(), id, getManagedDataObjectType().getTargetType()) + : current; + + LOG.debug("{}: Subtree: {} read successfully. Result: {}", this, id, readSubtree); + return readSubtree; + } + } + + /** + * Fill in current node's attributes + * + * @param id {@link InstanceIdentifier} pointing to current node. In case of keyed list, key must be present. + * @param builder Builder object for current node where the read attributes must be placed + * @param ctx Current read context + */ + protected abstract void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final B builder, + @Nonnull final ReadContext ctx) throws ReadFailedException; + + /** + * Return new instance of a builder object for current node + * + * @param id {@link InstanceIdentifier} pointing to current node. In case of keyed list, key must be present. + * @return Builder object for current node type + */ + protected abstract B getBuilder(InstanceIdentifier id); + + // TODO move filtering out of here into a dedicated Filter ifc + @Nonnull + private static Optional filterSubtree(@Nonnull final DataObject parent, + @Nonnull final InstanceIdentifier absolutPath, + @Nonnull final Class managedType) { + // TODO is there a better way than reflection ? e.g. convert into NN and filter out with a utility + // FIXME this needs to be recursive. right now it expects only 1 additional element in ID + test + + final InstanceIdentifier.PathArgument nextId = + VppRWUtils.getNextId(absolutPath, InstanceIdentifier.create(parent.getClass())); + + Optional method = ReflectionUtils.findMethodReflex(managedType, "get", + Collections.>emptyList(), nextId.getType()); + + if (method.isPresent()) { + return Optional.fromNullable(filterSingle(parent, nextId, method.get())); + } else { + // List child nodes + method = ReflectionUtils.findMethodReflex(managedType, + "get" + nextId.getType().getSimpleName(), Collections.>emptyList(), List.class); + + if (method.isPresent()) { + return filterList(parent, nextId, method.get()); + } else { + throw new IllegalStateException( + "Unable to filter " + nextId + " from " + parent + " getters not found using reflexion"); + } + } + } + + @SuppressWarnings("unchecked") + private static Optional filterList(final DataObject parent, + final InstanceIdentifier.PathArgument nextId, + final Method method) { + final List invoke = (List) invoke(method, nextId, parent); + + checkArgument(nextId instanceof InstanceIdentifier.IdentifiableItem, + "Unable to perform wildcarded read for %s", nextId); + final Identifier key = ((InstanceIdentifier.IdentifiableItem) nextId).getKey(); + return Iterables.tryFind(invoke, new Predicate() { + @Override + public boolean apply(@Nullable final DataObject input) { + final Optional keyGetter = + ReflectionUtils.findMethodReflex(nextId.getType(), "get", + Collections.>emptyList(), key.getClass()); + final Object actualKey; + actualKey = invoke(keyGetter.get(), nextId, input); + return key.equals(actualKey); + } + }); + } + + private static DataObject filterSingle(final DataObject parent, + final InstanceIdentifier.PathArgument nextId, final Method method) { + return nextId.getType().cast(invoke(method, nextId, parent)); + } + + private static Object invoke(final Method method, + final InstanceIdentifier.PathArgument nextId, final DataObject parent) { + try { + return method.invoke(parent); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new IllegalArgumentException("Unable to get " + nextId + " from " + parent, e); + } + } + + @Override + public String toString() { + return String.format("Reader[%s]", getManagedDataObjectType().getTargetType().getSimpleName()); + } +} diff --git a/v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/CompositeChildVppReader.java b/v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/CompositeChildVppReader.java new file mode 100644 index 000000000..76e793dbe --- /dev/null +++ b/v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/CompositeChildVppReader.java @@ -0,0 +1,104 @@ +/* + * 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.facade.impl.read; + +import com.google.common.annotations.Beta; +import com.google.common.base.Optional; +import io.fd.honeycomb.v3po.vpp.facade.impl.util.VppRWUtils; +import io.fd.honeycomb.v3po.vpp.facade.read.ChildVppReader; +import io.fd.honeycomb.v3po.vpp.facade.read.ReadContext; +import io.fd.honeycomb.v3po.vpp.facade.read.ReadFailedException; +import io.fd.honeycomb.v3po.vpp.facade.spi.read.ChildVppReaderCustomizer; +import java.util.List; +import javax.annotation.Nonnull; +import javax.annotation.concurrent.ThreadSafe; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.Augmentation; +import org.opendaylight.yangtools.yang.binding.ChildOf; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Composite implementation of {@link ChildVppReader} able to place the read result into + * parent builder object. + */ +@Beta +@ThreadSafe +public final class CompositeChildVppReader> extends AbstractCompositeVppReader + implements ChildVppReader { + + private final ChildVppReaderCustomizer customizer; + + /** + * Create new {@link CompositeChildVppReader} + * + * @param managedDataObjectType Class object for managed data type + * @param childReaders Child nodes(container, list) readers + * @param augReaders Child augmentations readers + * @param customizer Customizer instance to customize this generic reader + * + */ + public CompositeChildVppReader(@Nonnull final Class managedDataObjectType, + @Nonnull final List>> childReaders, + @Nonnull final List>> augReaders, + @Nonnull final ChildVppReaderCustomizer customizer) { + super(managedDataObjectType, childReaders, augReaders); + this.customizer = customizer; + } + + /** + * @see {@link CompositeChildVppReader#CompositeChildVppReader(Class, List, List, ChildVppReaderCustomizer)} + */ + public CompositeChildVppReader(@Nonnull final Class managedDataObjectType, + @Nonnull final List>> childReaders, + @Nonnull final ChildVppReaderCustomizer customizer) { + this(managedDataObjectType, childReaders, VppRWUtils.emptyAugReaderList(), customizer); + } + + /** + * @see {@link CompositeChildVppReader#CompositeChildVppReader(Class, List, List, ChildVppReaderCustomizer)} + */ + public CompositeChildVppReader(@Nonnull final Class managedDataObjectType, + @Nonnull final ChildVppReaderCustomizer customizer) { + this(managedDataObjectType, VppRWUtils.emptyChildReaderList(), VppRWUtils.emptyAugReaderList(), + customizer); + } + + @Override + public final void read(@Nonnull final InstanceIdentifier parentId, + @Nonnull final Builder parentBuilder, + @Nonnull final ReadContext ctx) throws ReadFailedException { + final Optional read = readCurrent(VppRWUtils.appendTypeToId(parentId, getManagedDataObjectType()), ctx); + + if(read.isPresent()) { + customizer.merge(parentBuilder, read.get()); + } + } + + @Override + protected void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final B builder, + @Nonnull final ReadContext ctx) + throws ReadFailedException { + customizer.readCurrentAttributes(id, builder, ctx.getContext()); + } + + @Override + protected B getBuilder(@Nonnull final InstanceIdentifier id) { + return customizer.getBuilder(id); + } + +} diff --git a/v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/CompositeListVppReader.java b/v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/CompositeListVppReader.java new file mode 100644 index 000000000..fcfa8b428 --- /dev/null +++ b/v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/CompositeListVppReader.java @@ -0,0 +1,137 @@ +/* + * 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.facade.impl.read; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.annotations.Beta; +import com.google.common.base.Optional; +import io.fd.honeycomb.v3po.vpp.facade.impl.util.VppRWUtils; +import io.fd.honeycomb.v3po.vpp.facade.read.ChildVppReader; +import io.fd.honeycomb.v3po.vpp.facade.read.ListVppReader; +import io.fd.honeycomb.v3po.vpp.facade.read.ReadContext; +import io.fd.honeycomb.v3po.vpp.facade.read.ReadFailedException; +import io.fd.honeycomb.v3po.vpp.facade.spi.read.ListVppReaderCustomizer; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nonnull; +import javax.annotation.concurrent.ThreadSafe; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.Augmentation; +import org.opendaylight.yangtools.yang.binding.ChildOf; +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.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Composite implementation of {@link io.fd.honeycomb.v3po.vpp.facade.read.ChildVppReader} able to place the read result into parent builder object intended + * for list node type. + * + * This reader checks if the IDs are wildcarded in which case it performs read of all list entries. In case the ID has a + * key, it reads only the specified value. + */ +@Beta +@ThreadSafe +public final class CompositeListVppReader, K extends Identifier, B extends Builder> + extends AbstractCompositeVppReader implements ChildVppReader, ListVppReader { + + private static final Logger LOG = LoggerFactory.getLogger(CompositeListVppReader.class); + + private final ListVppReaderCustomizer customizer; + + /** + * Create new {@link CompositeListVppReader} + * + * @param managedDataObjectType Class object for managed data type. Must come from a list node type. + * @param childReaders Child nodes(container, list) readers + * @param augReaders Child augmentations readers + * @param customizer Customizer instance to customize this generic reader + */ + public CompositeListVppReader(@Nonnull final Class managedDataObjectType, + @Nonnull final List>> childReaders, + @Nonnull final List>> augReaders, + @Nonnull final ListVppReaderCustomizer customizer) { + super(managedDataObjectType, childReaders, augReaders); + this.customizer = customizer; + } + + /** + * @see {@link CompositeListVppReader#CompositeListVppReader(Class, List, List, ListVppReaderCustomizer)} + */ + public CompositeListVppReader(@Nonnull final Class managedDataObjectType, + @Nonnull final List>> childReaders, + @Nonnull final ListVppReaderCustomizer customizer) { + this(managedDataObjectType, childReaders, VppRWUtils.emptyAugReaderList(), customizer); + } + + /** + * @see {@link CompositeListVppReader#CompositeListVppReader(Class, List, List, ListVppReaderCustomizer)} + */ + public CompositeListVppReader(@Nonnull final Class managedDataObjectType, + @Nonnull final ListVppReaderCustomizer customizer) { + this(managedDataObjectType, VppRWUtils.emptyChildReaderList(), VppRWUtils.emptyAugReaderList(), + customizer); + } + + @Override + public void read(@Nonnull final InstanceIdentifier id, + @Nonnull final Builder parentBuilder, + @Nonnull final ReadContext ctx) throws ReadFailedException { + // Create ID pointing to current node + final InstanceIdentifier currentId = VppRWUtils.appendTypeToId(id, getManagedDataObjectType()); + // Read all, since current ID is definitely wildcarded + final List ifcs = readList(currentId, ctx); + customizer.merge(parentBuilder, ifcs); + } + + @Override + @Nonnull + public List readList(@Nonnull final InstanceIdentifier id, + @Nonnull final ReadContext ctx) throws ReadFailedException { + LOG.trace("{}: Reading all list entries", this); + final List allIds = customizer.getAllIds(id, ctx.getContext()); + LOG.debug("{}: Reading list entries for: {}", this, allIds); + + final ArrayList allEntries = new ArrayList<>(allIds.size()); + for (K key : allIds) { + final InstanceIdentifier.IdentifiableItem currentBdItem = + VppRWUtils.getCurrentIdItem(id, key); + final InstanceIdentifier keyedId = VppRWUtils.replaceLastInId(id, currentBdItem); + final Optional read = readCurrent(keyedId, ctx); + final DataObject singleItem = read.get(); + checkArgument(getManagedDataObjectType().getTargetType().isAssignableFrom(singleItem.getClass())); + allEntries.add(getManagedDataObjectType().getTargetType().cast(singleItem)); + } + return allEntries; + } + + @Override + protected void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final B builder, + @Nonnull final ReadContext ctx) + throws ReadFailedException { + customizer.readCurrentAttributes(id, builder, ctx.getContext()); + } + + @Override + protected B getBuilder(@Nonnull final InstanceIdentifier id) { + return customizer.getBuilder(id); + } + +} diff --git a/v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/CompositeRootVppReader.java b/v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/CompositeRootVppReader.java new file mode 100644 index 000000000..95f2a8eec --- /dev/null +++ b/v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/CompositeRootVppReader.java @@ -0,0 +1,91 @@ +/* + * 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.facade.impl.read; + +import com.google.common.annotations.Beta; +import io.fd.honeycomb.v3po.vpp.facade.impl.util.VppRWUtils; +import io.fd.honeycomb.v3po.vpp.facade.read.ChildVppReader; +import io.fd.honeycomb.v3po.vpp.facade.read.ReadContext; +import io.fd.honeycomb.v3po.vpp.facade.read.ReadFailedException; +import io.fd.honeycomb.v3po.vpp.facade.read.VppReader; +import io.fd.honeycomb.v3po.vpp.facade.spi.read.RootVppReaderCustomizer; +import java.util.List; +import javax.annotation.Nonnull; +import javax.annotation.concurrent.ThreadSafe; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.Augmentation; +import org.opendaylight.yangtools.yang.binding.ChildOf; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Composite implementation of {@link io.fd.honeycomb.v3po.vpp.facade.read.VppReader} + */ +@Beta +@ThreadSafe +public final class CompositeRootVppReader> extends AbstractCompositeVppReader + implements VppReader { + + private final RootVppReaderCustomizer customizer; + + /** + * Create new {@link CompositeRootVppReader} + * + * @param managedDataObjectType Class object for managed data type + * @param childReaders Child nodes(container, list) readers + * @param augReaders Child augmentations readers + * @param customizer Customizer instance to customize this generic reader + * + */ + public CompositeRootVppReader(@Nonnull final Class managedDataObjectType, + @Nonnull final List>> childReaders, + @Nonnull final List>> augReaders, + @Nonnull final RootVppReaderCustomizer customizer) { + super(managedDataObjectType, childReaders, augReaders); + this.customizer = customizer; + } + + /** + * @see {@link CompositeRootVppReader#CompositeRootVppReader(Class, List, List, RootVppReaderCustomizer)} + */ + public CompositeRootVppReader(@Nonnull final Class managedDataObjectType, + @Nonnull final List>> childReaders, + @Nonnull final RootVppReaderCustomizer customizer) { + this(managedDataObjectType, childReaders, VppRWUtils.emptyAugReaderList(), customizer); + } + + /** + * @see {@link CompositeRootVppReader#CompositeRootVppReader(Class, List, List, RootVppReaderCustomizer)} + */ + public CompositeRootVppReader(@Nonnull final Class managedDataObjectType, + @Nonnull final RootVppReaderCustomizer customizer) { + this(managedDataObjectType, VppRWUtils.emptyChildReaderList(), VppRWUtils.emptyAugReaderList(), + customizer); + } + + @Override + protected void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final B builder, + @Nonnull final ReadContext ctx) throws ReadFailedException { + customizer.readCurrentAttributes(id, builder, ctx.getContext()); + } + + @Override + protected B getBuilder(@Nonnull final InstanceIdentifier id) { + return customizer.getBuilder(id); + } + +} diff --git a/v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/AbstractCompositeVppWriter.java b/v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/AbstractCompositeVppWriter.java new file mode 100644 index 000000000..add62e2ba --- /dev/null +++ b/v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/AbstractCompositeVppWriter.java @@ -0,0 +1,270 @@ +/* + * 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.facade.impl.write; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.base.Optional; +import com.google.common.collect.Lists; +import io.fd.honeycomb.v3po.vpp.facade.VppException; +import io.fd.honeycomb.v3po.vpp.facade.impl.util.VppRWUtils; +import io.fd.honeycomb.v3po.vpp.facade.write.ChildVppWriter; +import io.fd.honeycomb.v3po.vpp.facade.write.VppWriter; +import io.fd.honeycomb.v3po.vpp.facade.write.WriteContext; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.opendaylight.yangtools.yang.binding.Augmentation; +import org.opendaylight.yangtools.yang.binding.ChildOf; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class AbstractCompositeVppWriter implements VppWriter { + + private static final Logger LOG = LoggerFactory.getLogger(AbstractCompositeVppWriter.class); + + private final Map, ChildVppWriter>> childWriters; + private final Map, ChildVppWriter>> augWriters; + private final InstanceIdentifier instanceIdentifier; + + public AbstractCompositeVppWriter(final Class type, + final List>> childWriters, + final List>> augWriters) { + this.instanceIdentifier = InstanceIdentifier.create(type); + this.childWriters = VppRWUtils.uniqueLinkedIndex(childWriters, VppRWUtils.MANAGER_CLASS_FUNCTION); + this.augWriters = VppRWUtils.uniqueLinkedIndex(augWriters, VppRWUtils.MANAGER_CLASS_AUG_FUNCTION); + } + + protected void writeCurrent(final InstanceIdentifier id, final D data, final WriteContext ctx) { + LOG.debug("{}: Writing current: {} data: {}", this, id, data); + + LOG.trace("{}: Writing current attributes", this); + writeCurrentAttributes(id, data, ctx); + + for (ChildVppWriter> child : childWriters.values()) { + LOG.debug("{}: Writing child in: {}", this, child); + child.writeChild(id, data, ctx); + } + + for (ChildVppWriter> child : augWriters.values()) { + LOG.debug("{}: Writing augment in: {}", this, child); + child.writeChild(id, data, ctx); + } + + LOG.debug("{}: Current node written successfully", this); + } + + protected void updateCurrent(final InstanceIdentifier id, final D dataBefore, final D dataAfter, + final WriteContext ctx) { + LOG.debug("{}: Updating current: {} dataBefore: {}, datAfter: {}", this, id, dataBefore, dataAfter); + + if(dataBefore.equals(dataAfter)) { + LOG.debug("{}: Skipping current(no update): {}", this, id); + // No change, ignore + return; + } + + LOG.trace("{}: Updating current attributes", this); + updateCurrentAttributes(id, dataBefore, dataAfter, ctx); + + for (ChildVppWriter> child : childWriters.values()) { + LOG.debug("{}: Updating child in: {}", this, child); + child.updateChild(id, dataBefore, dataAfter, ctx); + } + + for (ChildVppWriter> child : augWriters.values()) { + LOG.debug("{}: Updating augment in: {}", this, child); + child.updateChild(id, dataBefore, dataAfter, ctx); + } + + LOG.debug("{}: Current node updated successfully", this); + } + + protected void deleteCurrent(final InstanceIdentifier id, final D dataBefore, final WriteContext ctx) { + LOG.debug("{}: Deleting current: {} dataBefore: {}", this, id, dataBefore); + + // delete in reversed order + for (ChildVppWriter> child : reverseCollection(augWriters.values())) { + LOG.debug("{}: Deleting augment in: {}", this, child); + child.deleteChild(id, dataBefore, ctx); + } + + for (ChildVppWriter> child : reverseCollection(childWriters.values())) { + LOG.debug("{}: Deleting child in: {}", this, child); + child.deleteChild(id, dataBefore, ctx); + } + + LOG.trace("{}: Deleting current attributes", this); + deleteCurrentAttributes(id, dataBefore, ctx); + } + + @SuppressWarnings("unchecked") + @Override + public void update(@Nonnull final InstanceIdentifier id, + @Nullable final DataObject dataBefore, + @Nullable final DataObject dataAfter, + @Nonnull final WriteContext ctx) throws VppException { + LOG.debug("{}: Updating : {}", this, id); + LOG.trace("{}: Updating : {}, from: {} to: {}", this, id, dataBefore, dataAfter); + + if (idPointsToCurrent(id)) { + if(isWrite(dataBefore, dataAfter)) { + writeCurrent((InstanceIdentifier) id, castToManaged(dataAfter), ctx); + } else if(isDelete(dataBefore, dataAfter)) { + deleteCurrent((InstanceIdentifier) id, castToManaged(dataBefore), ctx); + } else { + checkArgument(dataBefore != null && dataAfter != null, "No data to process"); + updateCurrent((InstanceIdentifier) id, castToManaged(dataBefore), castToManaged(dataAfter), ctx); + } + } else { + if (isWrite(dataBefore, dataAfter)) { + writeSubtree(id, dataAfter, ctx); + } else if (isDelete(dataBefore, dataAfter)) { + deleteSubtree(id, dataBefore, ctx); + } else { + checkArgument(dataBefore != null && dataAfter != null, "No data to process"); + updateSubtree(id, dataBefore, dataAfter, ctx); + } + } + } + + private void checkDataType(final @Nullable DataObject dataAfter) { + checkArgument(getManagedDataObjectType().getTargetType().isAssignableFrom(dataAfter.getClass())); + } + + private D castToManaged(final DataObject data) { + checkDataType(data); + return getManagedDataObjectType().getTargetType().cast(data); + } + + private static boolean isWrite(final DataObject dataBefore, + final DataObject dataAfter) { + return dataBefore == null && dataAfter != null; + } + + private static boolean isDelete(final DataObject dataBefore, + final DataObject dataAfter) { + return dataAfter == null && dataBefore != null; + } + + private void writeSubtree(final InstanceIdentifier id, + final DataObject dataAfter, final WriteContext ctx) throws VppException { + LOG.debug("{}: Writing subtree: {}", this, id); + final VppWriter> vppWriter = getNextWriter(id); + + if (vppWriter != null) { + LOG.debug("{}: Writing subtree: {} in: {}", this, id, vppWriter); + vppWriter.update(id, null, dataAfter, ctx); + } else { + // If there's no dedicated writer, use write current + // But we need current data after to do so + final InstanceIdentifier currentId = VppRWUtils.cutId(id, getManagedDataObjectType()); + Optional currentDataAfter = ctx.readAfter(currentId); + LOG.debug("{}: Dedicated subtree writer missing for: {}. Writing current.", this, + VppRWUtils.getNextId(id, getManagedDataObjectType()).getType(), currentDataAfter); + writeCurrent(currentId, castToManaged(currentDataAfter.get()), ctx); + } + } + + private boolean idPointsToCurrent(final @Nonnull InstanceIdentifier id) { + return id.getTargetType().equals(getManagedDataObjectType().getTargetType()); + } + + @SuppressWarnings("unchecked") + private void deleteSubtree(final InstanceIdentifier id, + final DataObject dataBefore, final WriteContext ctx) throws VppException { + LOG.debug("{}: Deleting subtree: {}", this, id); + final VppWriter> vppWriter = getNextWriter(id); + + if (vppWriter != null) { + LOG.debug("{}: Deleting subtree: {} in: {}", this, id, vppWriter); + vppWriter.update(id, dataBefore, null, ctx); + } else { + updateSubtreeFromCurrent(id, ctx); + } + } + + @SuppressWarnings("unchecked") + private void updateSubtreeFromCurrent(final InstanceIdentifier id, final WriteContext ctx) { + final InstanceIdentifier currentId = VppRWUtils.cutId(id, getManagedDataObjectType()); + Optional currentDataBefore = ctx.readBefore(currentId); + Optional currentDataAfter = ctx.readAfter(currentId); + LOG.debug("{}: Dedicated subtree writer missing for: {}. Updating current without subtree", this, + VppRWUtils.getNextId(id, getManagedDataObjectType()).getType(), currentDataAfter); + updateCurrent((InstanceIdentifier) id, castToManaged(currentDataBefore.orNull()), + castToManaged(currentDataAfter.orNull()), ctx); + } + + @SuppressWarnings("unchecked") + private void updateSubtree(final InstanceIdentifier id, + final DataObject dataBefore, + final DataObject dataAfter, + final WriteContext ctx) throws VppException { + LOG.debug("{}: Updating subtree: {}", this, id); + final VppWriter> vppWriter = getNextWriter(id); + + if (vppWriter != null) { + LOG.debug("{}: Updating subtree: {} in: {}", this, id, vppWriter); + vppWriter.update(id, dataBefore, dataAfter, ctx); + } else { + updateSubtreeFromCurrent(id, ctx); + } + } + + private VppWriter> getNextWriter(final InstanceIdentifier id) { + final Class next = VppRWUtils.getNextId(id, getManagedDataObjectType()).getType(); + return childWriters.get(next); + } + + private static List reverseCollection(final Collection original) { + // TODO find a better reverse mechanism (probably a different collection for child writers is necessary) + final ArrayList list = Lists.newArrayList(original); + Collections.reverse(list); + return list; + } + + protected abstract void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final D data, + @Nonnull final WriteContext ctx); + + protected abstract void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final D dataBefore, + @Nonnull final WriteContext ctx); + + protected abstract void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final D dataBefore, + @Nonnull final D dataAfter, + @Nonnull final WriteContext ctx); + + @Nonnull + @Override + public InstanceIdentifier getManagedDataObjectType() { + return instanceIdentifier; + } + + + @Override + public String toString() { + return String.format("Writer[%s]", getManagedDataObjectType().getTargetType().getSimpleName()); + } +} diff --git a/v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/CompositeChildVppWriter.java b/v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/CompositeChildVppWriter.java new file mode 100644 index 000000000..a11004e86 --- /dev/null +++ b/v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/CompositeChildVppWriter.java @@ -0,0 +1,105 @@ +/* + * 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.facade.impl.write; + +import com.google.common.base.Optional; +import io.fd.honeycomb.v3po.vpp.facade.impl.util.VppRWUtils; +import io.fd.honeycomb.v3po.vpp.facade.spi.write.ChildVppWriterCustomizer; +import io.fd.honeycomb.v3po.vpp.facade.write.ChildVppWriter; +import io.fd.honeycomb.v3po.vpp.facade.write.WriteContext; +import java.util.List; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.Augmentation; +import org.opendaylight.yangtools.yang.binding.ChildOf; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class CompositeChildVppWriter extends AbstractCompositeVppWriter + implements ChildVppWriter { + + private final ChildVppWriterCustomizer customizer; + + public CompositeChildVppWriter(@Nonnull final Class type, + @Nonnull final List>> childWriters, + @Nonnull final List>> augWriters, + @Nonnull final ChildVppWriterCustomizer customizer) { + super(type, childWriters, augWriters); + this.customizer = customizer; + } + + public CompositeChildVppWriter(@Nonnull final Class type, + @Nonnull final List>> childWriters, + @Nonnull final ChildVppWriterCustomizer customizer) { + this(type, childWriters, VppRWUtils.emptyAugWriterList(), customizer); + } + + public CompositeChildVppWriter(@Nonnull final Class type, + @Nonnull final ChildVppWriterCustomizer customizer) { + this(type, VppRWUtils.emptyChildWriterList(), VppRWUtils.emptyAugWriterList(), customizer); + } + + @Override + protected void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D data, + @Nonnull final WriteContext ctx) { + customizer.writeCurrentAttributes(id, data, ctx.getContext()); + } + + @Override + protected void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D dataBefore, + @Nonnull WriteContext ctx) { + customizer.deleteCurrentAttributes(id, dataBefore, ctx.getContext()); + } + + @Override + protected void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D dataBefore, + @Nonnull final D dataAfter, @Nonnull WriteContext ctx) { + customizer.updateCurrentAttributes(id, dataBefore, dataAfter, ctx.getContext()); + } + + @Override + public void writeChild(@Nonnull final InstanceIdentifier parentId, + @Nonnull final DataObject parentData, @Nonnull WriteContext ctx) { + final InstanceIdentifier currentId = VppRWUtils.appendTypeToId(parentId, getManagedDataObjectType()); + final Optional currentData = customizer.extract(currentId, parentData); + if(currentData.isPresent()) { + writeCurrent(currentId, currentData.get(), ctx); + } + } + + @Override + public void deleteChild(@Nonnull final InstanceIdentifier parentId, + @Nonnull final DataObject parentData, + @Nonnull final WriteContext ctx) { + final InstanceIdentifier currentId = VppRWUtils.appendTypeToId(parentId, getManagedDataObjectType()); + final Optional currentData = customizer.extract(currentId, parentData); + if(currentData.isPresent()) { + deleteCurrent(currentId, currentData.get(), ctx); + } + } + + @Override + public void updateChild(@Nonnull final InstanceIdentifier parentId, + @Nonnull final DataObject parentDataBefore, @Nonnull final DataObject parentDataAfter, + @Nonnull final WriteContext ctx) { + final InstanceIdentifier currentId = VppRWUtils.appendTypeToId(parentId, getManagedDataObjectType()); + final Optional before = customizer.extract(currentId, parentDataBefore); + final Optional after = customizer.extract(currentId, parentDataAfter); + if(before.isPresent() && after.isPresent()) { + updateCurrent(currentId, before.get(), after.get(), ctx); + } + } +} diff --git a/v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/CompositeListVppWriter.java b/v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/CompositeListVppWriter.java new file mode 100644 index 000000000..805d951f9 --- /dev/null +++ b/v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/CompositeListVppWriter.java @@ -0,0 +1,178 @@ +/* + * 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.facade.impl.write; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import io.fd.honeycomb.v3po.vpp.facade.impl.util.VppRWUtils; +import io.fd.honeycomb.v3po.vpp.facade.spi.write.ListVppWriterCustomizer; +import io.fd.honeycomb.v3po.vpp.facade.write.ChildVppWriter; +import io.fd.honeycomb.v3po.vpp.facade.write.WriteContext; +import java.util.List; +import java.util.Map; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.Augmentation; +import org.opendaylight.yangtools.yang.binding.ChildOf; +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; + +public class CompositeListVppWriter, K extends Identifier> extends AbstractCompositeVppWriter + implements ChildVppWriter { + + public static final Function INDEX_FUNCTION = new Function() { + @Override + public Object apply(final DataObject input) { + return input instanceof Identifiable + ? ((Identifiable) input).getKey() + : input; + } + }; + + + private final ListVppWriterCustomizer customizer; + + public CompositeListVppWriter(@Nonnull final Class type, + @Nonnull final List>> childWriters, + @Nonnull final List>> augWriters, + @Nonnull final ListVppWriterCustomizer customizer) { + super(type, childWriters, augWriters); + this.customizer = customizer; + } + + public CompositeListVppWriter(@Nonnull final Class type, + @Nonnull final List>> childWriters, + @Nonnull final ListVppWriterCustomizer customizer) { + this(type, childWriters, VppRWUtils.emptyAugWriterList(), customizer); + } + + public CompositeListVppWriter(@Nonnull final Class type, + @Nonnull final ListVppWriterCustomizer customizer) { + this(type, VppRWUtils.emptyChildWriterList(), VppRWUtils.emptyAugWriterList(), customizer); + + } + + @Override + protected void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D data, + @Nonnull final WriteContext ctx) { + customizer.writeCurrentAttributes(id, data, ctx.getContext()); + } + + @Override + protected void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D dataBefore, + @Nonnull final WriteContext ctx) { + customizer.deleteCurrentAttributes(id, dataBefore, ctx.getContext()); + } + + @Override + protected void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D dataBefore, + @Nonnull final D dataAfter, @Nonnull final WriteContext ctx) { + customizer.updateCurrentAttributes(id, dataBefore, dataAfter, ctx.getContext()); + } + + @Override + public void writeChild(@Nonnull final InstanceIdentifier parentId, + @Nonnull final DataObject parentData, + @Nonnull final WriteContext ctx) { + final InstanceIdentifier currentId = VppRWUtils.appendTypeToId(parentId, getManagedDataObjectType()); + final List currentData = customizer.extract(currentId, parentData); + for (D entry : currentData) { + writeCurrent(currentId, entry, ctx); + } + } + + @Override + public void deleteChild(@Nonnull final InstanceIdentifier parentId, + @Nonnull final DataObject parentDataBefore, + @Nonnull final WriteContext ctx) { + final InstanceIdentifier currentId = VppRWUtils.appendTypeToId(parentId, getManagedDataObjectType()); + final List dataBefore = customizer.extract(currentId, parentDataBefore); + for (D entry : dataBefore) { + deleteCurrent(currentId, entry, ctx); + } + } + + @Override + public void updateChild(@Nonnull final InstanceIdentifier parentId, + @Nonnull final DataObject parentDataBefore, @Nonnull final DataObject parentDataAfter, + @Nonnull final WriteContext ctx) { + final InstanceIdentifier currentId = VppRWUtils.appendTypeToId(parentId, getManagedDataObjectType()); + final ImmutableMap + dataBefore = Maps.uniqueIndex(customizer.extract(currentId, parentDataBefore), INDEX_FUNCTION); + final ImmutableMap + dataAfter = Maps.uniqueIndex(customizer.extract(currentId, parentDataAfter), INDEX_FUNCTION); + + for (Map.Entry after : dataAfter.entrySet()) { + final D before = dataBefore.get(after.getKey()); + if(before == null) { + writeCurrent(currentId, after.getValue(), ctx); + } else { + updateCurrent(currentId, before, after.getValue(), ctx); + } + } + + // Delete the rest in dataBefore + for (Object deletedNodeKey : Sets.difference(dataBefore.keySet(), dataAfter.keySet())) { + final D deleted = dataBefore.get(deletedNodeKey); + deleteCurrent(currentId, deleted, ctx); + } + + } + + @Override + protected void writeCurrent(final InstanceIdentifier id, final D data, final WriteContext ctx) { + // Make sure the key is present + if(isWildcarded(id)) { + super.writeCurrent(getSpecificId(id, data), data, ctx); + } else { + super.writeCurrent(id, data, ctx); + } + } + + @Override + protected void updateCurrent(final InstanceIdentifier id, final D dataBefore, final D dataAfter, + final WriteContext ctx) { + // Make sure the key is present + if(isWildcarded(id)) { + super.updateCurrent(getSpecificId(id, dataBefore), dataBefore, dataAfter, ctx); + } else { + super.updateCurrent(id, dataBefore, dataAfter, ctx); + } + } + + @Override + protected void deleteCurrent(final InstanceIdentifier id, final D dataBefore, final WriteContext ctx) { + // Make sure the key is present + if(isWildcarded(id)) { + super.deleteCurrent(getSpecificId(id, dataBefore), dataBefore, ctx); + } else { + super.deleteCurrent(id, dataBefore, ctx); + } + } + + private boolean isWildcarded(final InstanceIdentifier id) { + return id.firstIdentifierOf(getManagedDataObjectType().getTargetType()).isWildcarded(); + } + + private InstanceIdentifier getSpecificId(final InstanceIdentifier currentId, final D current) { + return VppRWUtils.replaceLastInId(currentId, + new InstanceIdentifier.IdentifiableItem<>(currentId.getTargetType(), current.getKey())); + } +} diff --git a/v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/CompositeRootVppWriter.java b/v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/CompositeRootVppWriter.java new file mode 100644 index 000000000..7bcb8dbbb --- /dev/null +++ b/v3po/vpp-facade-impl/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/CompositeRootVppWriter.java @@ -0,0 +1,72 @@ +/* + * 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.facade.impl.write; + +import io.fd.honeycomb.v3po.vpp.facade.impl.util.VppRWUtils; +import io.fd.honeycomb.v3po.vpp.facade.spi.write.RootVppWriterCustomizer; +import io.fd.honeycomb.v3po.vpp.facade.write.ChildVppWriter; +import io.fd.honeycomb.v3po.vpp.facade.write.WriteContext; +import java.util.List; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.Augmentation; +import org.opendaylight.yangtools.yang.binding.ChildOf; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class CompositeRootVppWriter extends AbstractCompositeVppWriter { + + private final RootVppWriterCustomizer customizer; + + public CompositeRootVppWriter(@Nonnull final Class type, + @Nonnull final List>> childWriters, + @Nonnull final List>> augWriters, + @Nonnull final RootVppWriterCustomizer customizer) { + super(type, childWriters, augWriters); + this.customizer = customizer; + } + + public CompositeRootVppWriter(@Nonnull final Class type, + @Nonnull final List>> childWriters, + @Nonnull final RootVppWriterCustomizer customizer) { + this(type, childWriters, VppRWUtils.emptyAugWriterList(), customizer); + } + + public CompositeRootVppWriter(@Nonnull final Class type, + @Nonnull final RootVppWriterCustomizer customizer) { + this(type, VppRWUtils.emptyChildWriterList(), VppRWUtils.emptyAugWriterList(), customizer); + } + + @Override + protected void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D data, + @Nonnull final WriteContext ctx) { + customizer.writeCurrentAttributes(id, data, ctx.getContext()); + } + + @Override + protected void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D dataBefore, + @Nonnull final WriteContext ctx) { + customizer.deleteCurrentAttributes(id, dataBefore, ctx.getContext()); + } + + @Override + protected void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final D dataBefore, + @Nonnull final D dataAfter, + @Nonnull final WriteContext ctx) { + customizer.updateCurrentAttributes(id, dataBefore, dataAfter, ctx.getContext()); + } +} diff --git a/v3po/vpp-facade-impl/src/test/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/DelegatingWriterRegistryTest.java b/v3po/vpp-facade-impl/src/test/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/DelegatingWriterRegistryTest.java new file mode 100644 index 000000000..6730cfe26 --- /dev/null +++ b/v3po/vpp-facade-impl/src/test/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/DelegatingWriterRegistryTest.java @@ -0,0 +1,189 @@ +/* + * 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.facade.impl.write.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import io.fd.honeycomb.v3po.vpp.facade.VppException; +import io.fd.honeycomb.v3po.vpp.facade.impl.write.CompositeRootVppWriter; +import io.fd.honeycomb.v3po.vpp.facade.write.VppWriter; +import io.fd.honeycomb.v3po.vpp.facade.write.WriteContext; +import io.fd.honeycomb.v3po.vpp.facade.write.WriterRegistry; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class DelegatingWriterRegistryTest { + + private final InstanceIdentifier vppId; + private final InstanceIdentifier vppStateId; + private final InstanceIdentifier interfaceId; + + private WriteContext ctx; + private CompositeRootVppWriter vppWriter; + private CompositeRootVppWriter vppStateWriter; + private CompositeRootVppWriter interfacesWriter; + + private DelegatingWriterRegistry registry; + + public DelegatingWriterRegistryTest() { + vppId = InstanceIdentifier.create(Vpp.class); + vppStateId = InstanceIdentifier.create(VppState.class); + interfaceId = InstanceIdentifier.create(Interfaces.class); + } + + @SuppressWarnings("unchecked") + private CompositeRootVppWriter mockWriter(Class clazz) { + final CompositeRootVppWriter mock = (CompositeRootVppWriter) Mockito.mock(CompositeRootVppWriter.class); + doReturn(InstanceIdentifier.create(clazz)).when(mock).getManagedDataObjectType(); + return mock; + } + + private DataObject mockDataObject(final String name, final Class classToMock) { + final DataObject dataBefore = mock(classToMock, name); + doReturn(classToMock).when(dataBefore).getImplementedInterface(); + return dataBefore; + } + + @SuppressWarnings("unchecked") + private static Map, DataObject> asMap(DataObject... objects) { + final Map, DataObject> map = new HashMap<>(); + for (DataObject object : objects) { + final Class implementedInterface = + (Class) object.getImplementedInterface(); + final InstanceIdentifier id = InstanceIdentifier.create(implementedInterface); + map.put(id, object); + } + return map; + } + + @Before + public void setUp() { + ctx = mock(WriteContext.class); + vppWriter = mockWriter(Vpp.class); + vppStateWriter = mockWriter(VppState.class); + interfacesWriter = mockWriter(Interfaces.class); + + final List> writers = new ArrayList<>(); + writers.add(vppWriter); + writers.add(vppStateWriter); + writers.add(interfacesWriter); + + registry = new DelegatingWriterRegistry(writers); + } + + @Test(expected = UnsupportedOperationException.class) + public void testGetManagedDataObjectType() { + registry.getManagedDataObjectType(); + } + + @Test + public void testBulkUpdateRevert() throws Exception { + // Prepare data changes: + final DataObject dataBefore1 = mockDataObject("Vpp before", Vpp.class); + final DataObject dataAfter1 = mockDataObject("Vpp after", Vpp.class); + + final DataObject dataBefore2 = mockDataObject("VppState before", VppState.class); + final DataObject dataAfter2 = mockDataObject("VppState after", VppState.class); + + // Fail on update + doThrow(new VppException("vpp failed")).when(vppStateWriter) + .update(vppStateId, dataBefore2, dataAfter2, ctx); + + // Run the test + try { + registry.update(asMap(dataBefore1, dataBefore2), asMap(dataAfter1, dataAfter2), ctx); + } catch (WriterRegistry.BulkUpdateException e) { + // Check second update failed + assertEquals(vppStateId, e.getFailedId()); + verify(vppWriter).update(vppId, dataBefore1, dataAfter1, ctx); + verify(vppStateWriter).update(vppStateId, dataBefore2, dataAfter2, ctx); + + // Try to revert changes + e.revertChanges(); + + // Check revert was successful + verify(vppWriter).update(vppId, dataAfter1, dataBefore1, ctx); + verify(vppStateWriter, never()).update(vppStateId, dataAfter2, dataBefore2, ctx); + + return; + } + fail("BulkUpdateException expected"); + } + + @Test + public void testBulkUpdateRevertFail() throws Exception { + // Prepare data changes: + final DataObject dataBefore1 = mockDataObject("Vpp before", Vpp.class); + final DataObject dataAfter1 = mockDataObject("Vpp after", Vpp.class); + + final DataObject dataBefore2 = mockDataObject("VppState before", VppState.class); + final DataObject dataAfter2 = mockDataObject("VppState after", VppState.class); + + final DataObject dataBefore3 = mockDataObject("Interfaces before", Interfaces.class); + final DataObject dataAfter3 = mockDataObject("Interfaces after", Interfaces.class); + + // Fail on the third update + doThrow(new VppException("vpp failed")).when(interfacesWriter) + .update(interfaceId, dataBefore3, dataAfter3, ctx); + + // Fail on the second revert + doThrow(new VppException("vpp failed again")).when(vppWriter) + .update(vppId, dataAfter1, dataBefore1, ctx); + + // Run the test + try { + registry.update(asMap(dataBefore1, dataBefore2, dataBefore3), asMap(dataAfter1, dataAfter2, dataAfter3), ctx); + } catch (WriterRegistry.BulkUpdateException e) { + // Check third update failed + assertEquals(interfaceId, e.getFailedId()); + verify(vppWriter).update(vppId, dataBefore1, dataAfter1, ctx); + verify(vppStateWriter).update(vppStateId, dataBefore2, dataAfter2, ctx); + verify(interfacesWriter).update(interfaceId, dataBefore3, dataAfter3, ctx); + + // Try to revert changes + try { + e.revertChanges(); + } catch (WriterRegistry.Reverter.RevertFailedException e2) { + // Check second revert failed + assertEquals(Collections.singletonList(vppId), e2.getNotRevertedChanges()); + verify(vppWriter).update(vppId, dataAfter1, dataBefore1, ctx); + verify(vppStateWriter).update(vppStateId, dataAfter2, dataBefore2, ctx); + verify(interfacesWriter, never()).update(interfaceId, dataAfter3, dataBefore3, ctx); + return; + } + fail("WriterRegistry.Revert.RevertFailedException expected"); + } + fail("BulkUpdateException expected"); + } +} \ No newline at end of file diff --git a/v3po/vpp-facade-impl/src/test/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/TransactionWriteContextTest.java b/v3po/vpp-facade-impl/src/test/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/TransactionWriteContextTest.java new file mode 100644 index 000000000..0e46e2fa4 --- /dev/null +++ b/v3po/vpp-facade-impl/src/test/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/TransactionWriteContextTest.java @@ -0,0 +1,138 @@ +/* + * 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.facade.impl.write.util; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +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.vpp.facade.Context; +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.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; +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 TransactionWriteContextTest { + + @Mock + private BindingNormalizedNodeSerializer serializer; + @Mock + private DOMDataReadOnlyTransaction beforeTx; + @Mock + private DOMDataReadOnlyTransaction afterTx; + @Mock + private CheckedFuture>, ReadFailedException> future; + @Mock + private Optional> optional; + @Mock + private Map.Entry entry; + + private TransactionWriteContext transactionWriteContext; + + @Before + public void setUp() { + initMocks(this); + transactionWriteContext = new TransactionWriteContext(serializer, beforeTx, afterTx); + } + + @Test + public void testReadBeforeNoData() throws Exception { + when(beforeTx.read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn(future); + when(future.checkedGet()).thenReturn(optional); + when(optional.isPresent()).thenReturn(false); + + final InstanceIdentifier instanceId = + InstanceIdentifier.create(Vpp.class).child(BridgeDomains.class).child(BridgeDomain.class); + + final Optional dataObjects = transactionWriteContext.readBefore(instanceId); + assertNotNull(dataObjects); + assertFalse(dataObjects.isPresent()); + + verify(serializer).toYangInstanceIdentifier(instanceId); + verify(serializer, never()).fromNormalizedNode(any(YangInstanceIdentifier.class), any(NormalizedNode.class)); + } + + + @Test + public void testReadBefore() throws Exception { + when(beforeTx.read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn(future); + when(future.checkedGet()).thenReturn(optional); + when(optional.isPresent()).thenReturn(true); + + final InstanceIdentifier instanceId = + InstanceIdentifier.create(Vpp.class).child(BridgeDomains.class).child(BridgeDomain.class); + final YangInstanceIdentifier yangId = YangInstanceIdentifier.builder().node(VppState.QNAME).node( + BridgeDomains.QNAME).node(BridgeDomain.QNAME).build(); + when(serializer.toYangInstanceIdentifier(any(InstanceIdentifier.class))).thenReturn(yangId); + when(serializer.fromNormalizedNode(eq(yangId), any(NormalizedNode.class))).thenReturn(entry); + when(entry.getValue()).thenReturn(mock(DataObject.class)); + + final Optional dataObjects = transactionWriteContext.readBefore(instanceId); + assertNotNull(dataObjects); + assertTrue(dataObjects.isPresent()); + + verify(serializer).toYangInstanceIdentifier(instanceId); + verify(serializer).fromNormalizedNode(eq(yangId), any(NormalizedNode.class)); + } + + @Test(expected = IllegalStateException.class) + public void testReadBeforeFailed() throws Exception { + when(beforeTx.read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn(future); + when(future.checkedGet()).thenThrow(ReadFailedException.class); + transactionWriteContext.readBefore(mock(InstanceIdentifier.class)); + } + + @Test(expected = IllegalStateException.class) + public void testReadAfterFailed() throws Exception { + when(afterTx.read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn(future); + when(future.checkedGet()).thenThrow(ReadFailedException.class); + transactionWriteContext.readAfter(mock(InstanceIdentifier.class)); + } + + @Test + public void testGetContext() throws Exception { + assertNotNull(transactionWriteContext.getContext()); + } + + @Test + public void testClose() throws Exception { + final Context context = transactionWriteContext.getContext(); + transactionWriteContext.close(); + // TODO verify context was closed + } +} \ No newline at end of file diff --git a/v3po/vpp-facade-spi/pom.xml b/v3po/vpp-facade-spi/pom.xml new file mode 100644 index 000000000..87f9c2848 --- /dev/null +++ b/v3po/vpp-facade-spi/pom.xml @@ -0,0 +1,72 @@ + + + + + io.fd.honeycomb.common + api-parent + 1.0.0-SNAPSHOT + ../../common/api-parent + + + 4.0.0 + io.fd.honeycomb.v3po + vpp-facade-spi + 1.0.0-SNAPSHOT + bundle + + + + + org.opendaylight.mdsal + mdsal-artifacts + 2.0.0-Beryllium + pom + import + + + + + + + com.google.guava + guava + + + ${project.groupId} + vpp-facade-api + ${project.version} + + + org.opendaylight.mdsal + mdsal-binding-api + + + + + junit + junit + test + + + org.mockito + mockito-all + test + + + + + diff --git a/v3po/vpp-facade-spi/src/main/java/io/fd/honeycomb/v3po/vpp/facade/spi/read/ChildVppReaderCustomizer.java b/v3po/vpp-facade-spi/src/main/java/io/fd/honeycomb/v3po/vpp/facade/spi/read/ChildVppReaderCustomizer.java new file mode 100644 index 000000000..376474301 --- /dev/null +++ b/v3po/vpp-facade-spi/src/main/java/io/fd/honeycomb/v3po/vpp/facade/spi/read/ChildVppReaderCustomizer.java @@ -0,0 +1,41 @@ +/* + * 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.facade.spi.read; + +import com.google.common.annotations.Beta; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; + +/** + * CompositeChildVppReader SPI to customize its behavior + * + * @param Specific DataObject derived type (Identifiable), that is handled by this customizer + * @param Specific Builder for handled type (C) + */ +@Beta +public interface ChildVppReaderCustomizer> extends + RootVppReaderCustomizer { + + // FIXME need to capture parent builder type, but that's inconvenient at best, is it ok to leave it Builder and + // cast in specific customizers ? ... probably better than adding another type parameter + + /** + * Merge read data into provided parent builder + */ + void merge(@Nonnull final Builder parentBuilder, @Nonnull final C readValue); +} diff --git a/v3po/vpp-facade-spi/src/main/java/io/fd/honeycomb/v3po/vpp/facade/spi/read/ListVppReaderCustomizer.java b/v3po/vpp-facade-spi/src/main/java/io/fd/honeycomb/v3po/vpp/facade/spi/read/ListVppReaderCustomizer.java new file mode 100644 index 000000000..610b2da8b --- /dev/null +++ b/v3po/vpp-facade-spi/src/main/java/io/fd/honeycomb/v3po/vpp/facade/spi/read/ListVppReaderCustomizer.java @@ -0,0 +1,54 @@ +/* + * 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.facade.spi.read; + +import com.google.common.annotations.Beta; +import io.fd.honeycomb.v3po.vpp.facade.Context; +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; + +/** + * CompositeListVppReader SPI to customize its behavior + * + * @param Specific DataObject derived type (Identifiable), that is handled by this customizer + * @param Specific Identifier for handled type (C) + * @param Specific Builder for handled type (C) + */ +@Beta +public interface ListVppReaderCustomizer, K extends Identifier, B extends Builder> + extends RootVppReaderCustomizer { + + /** + * Return list with IDs of all list nodes to be read. + * + * @param id Wildcarded ID pointing to list node managed by enclosing reader + * @param context Read context + */ + @Nonnull + List getAllIds(@Nonnull final InstanceIdentifier id, @Nonnull final Context context); + // TODO does it make sense with vpp APIs ? Should we replace it with a simple readAll ? + + /** + * Merge read data into provided parent builder + */ + void merge(@Nonnull final Builder builder, @Nonnull final List readData); +} diff --git a/v3po/vpp-facade-spi/src/main/java/io/fd/honeycomb/v3po/vpp/facade/spi/read/RootVppReaderCustomizer.java b/v3po/vpp-facade-spi/src/main/java/io/fd/honeycomb/v3po/vpp/facade/spi/read/RootVppReaderCustomizer.java new file mode 100644 index 000000000..8035933df --- /dev/null +++ b/v3po/vpp-facade-spi/src/main/java/io/fd/honeycomb/v3po/vpp/facade/spi/read/RootVppReaderCustomizer.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.facade.spi.read; + +import com.google.common.annotations.Beta; +import io.fd.honeycomb.v3po.vpp.facade.Context; +import io.fd.honeycomb.v3po.vpp.facade.read.ReadFailedException; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * CompositeRootVppReader SPI to customize its behavior + * + * @param Specific DataObject derived type, that is handled by this customizer + * @param Specific Builder for handled type (C) + */ +@Beta +public interface RootVppReaderCustomizer> { + + /** + * Creates new builder that will be used to build read value. + */ + @Nonnull + B getBuilder(@Nonnull final InstanceIdentifier id); + + + /** + * Adds current data (identified by id) to the provided builder. + * + * @param id id of current data object + * @param builder builder for creating read value + * @throws ReadFailedException if read was unsuccessful + */ + void readCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final B builder, + @Nonnull final Context ctx) throws ReadFailedException; +} diff --git a/v3po/vpp-facade-spi/src/main/java/io/fd/honeycomb/v3po/vpp/facade/spi/write/ChildVppWriterCustomizer.java b/v3po/vpp-facade-spi/src/main/java/io/fd/honeycomb/v3po/vpp/facade/spi/write/ChildVppWriterCustomizer.java new file mode 100644 index 000000000..7b7e257a2 --- /dev/null +++ b/v3po/vpp-facade-spi/src/main/java/io/fd/honeycomb/v3po/vpp/facade/spi/write/ChildVppWriterCustomizer.java @@ -0,0 +1,42 @@ +/* + * 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.facade.spi.write; + +import com.google.common.annotations.Beta; +import com.google.common.base.Optional; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * CompositeChildVppWriter SPI to customize its behavior + * + * @param Specific DataObject derived type (Identifiable), that is handled by this customizer + */ +@Beta +public interface ChildVppWriterCustomizer extends RootVppWriterCustomizer { + + /** + * Get child of parentData identified by currentId + * + * @param currentId Identifier(from root) of data being extracted + * @param parentData Parent data object from which managed data object must be extracted + */ + @Nonnull + Optional extract(@Nonnull final InstanceIdentifier currentId, @Nonnull final DataObject parentData); + +} diff --git a/v3po/vpp-facade-spi/src/main/java/io/fd/honeycomb/v3po/vpp/facade/spi/write/ListVppWriterCustomizer.java b/v3po/vpp-facade-spi/src/main/java/io/fd/honeycomb/v3po/vpp/facade/spi/write/ListVppWriterCustomizer.java new file mode 100644 index 000000000..b4bf1aa41 --- /dev/null +++ b/v3po/vpp-facade-spi/src/main/java/io/fd/honeycomb/v3po/vpp/facade/spi/write/ListVppWriterCustomizer.java @@ -0,0 +1,45 @@ +/* + * 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.facade.spi.write; + +import com.google.common.annotations.Beta; +import java.util.List; +import javax.annotation.Nonnull; +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; + +/** + * CompositeListVppWriter SPI to customize its behavior + * + * @param Specific DataObject derived type (Identifiable), that is handled by this customizer + * @param Specific Identifier for handled type (C) + */ +@Beta +public interface ListVppWriterCustomizer, K extends Identifier> extends RootVppWriterCustomizer { + + /** + * Get children of parentData identified by currentId + * + * @param currentId Identifier(from root) of data being extracted + * @param parentData Parent data object from which managed data object must be extracted + */ + @Nonnull + List extract(@Nonnull final InstanceIdentifier currentId, @Nonnull final DataObject parentData); + +} \ No newline at end of file diff --git a/v3po/vpp-facade-spi/src/main/java/io/fd/honeycomb/v3po/vpp/facade/spi/write/RootVppWriterCustomizer.java b/v3po/vpp-facade-spi/src/main/java/io/fd/honeycomb/v3po/vpp/facade/spi/write/RootVppWriterCustomizer.java new file mode 100644 index 000000000..1335e8afb --- /dev/null +++ b/v3po/vpp-facade-spi/src/main/java/io/fd/honeycomb/v3po/vpp/facade/spi/write/RootVppWriterCustomizer.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.vpp.facade.spi.write; + +import com.google.common.annotations.Beta; +import io.fd.honeycomb.v3po.vpp.facade.Context; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * CompositeRootVppReader SPI to customize its behavior + * + * @param Specific DataObject derived type, that is handled by this customizer + */ +@Beta +public interface RootVppWriterCustomizer { + + /** + * Handle write operation. C from CRUD. + * + * @param id Identifier(from root) of data being written + * @param dataAfter New data to be written + * @param writeContext Write context can be used to store any useful information and then utilized by other customizers + */ + void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final D dataAfter, + @Nonnull final Context writeContext); + + /** + * Handle update operation. U from CRUD. + * + * @param id Identifier(from root) of data being written + * @param dataBefore Old data + * @param dataAfter New, updated data + * @param writeContext Write context can be used to store any useful information and then utilized by other customizers + */ + void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final D dataBefore, + @Nonnull final D dataAfter, + @Nonnull final Context writeContext); + + /** + * Handle delete operation. D from CRUD. + * + * @param id Identifier(from root) of data being written + * @param dataBefore Old data being deleted + * @param writeContext Write context can be used to store any useful information and then utilized by other customizers + */ + void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final D dataBefore, + @Nonnull final Context writeContext); +} diff --git a/v3po/vpp-facade-utils/pom.xml b/v3po/vpp-facade-utils/pom.xml new file mode 100644 index 000000000..83c7d7415 --- /dev/null +++ b/v3po/vpp-facade-utils/pom.xml @@ -0,0 +1,95 @@ + + + + + io.fd.honeycomb.common + api-parent + 1.0.0-SNAPSHOT + ../../common/api-parent + + + 4.0.0 + io.fd.honeycomb.v3po + vpp-facade-utils + 1.0.0-SNAPSHOT + bundle + + + + + org.opendaylight.mdsal + mdsal-artifacts + 2.0.0-Beryllium + pom + import + + + org.opendaylight.controller + mdsal-artifacts + 1.3.0-Beryllium + pom + import + + + + + + + ${project.groupId} + vpp-facade-api + ${project.version} + + + ${project.groupId} + vpp-facade-spi + ${project.version} + + + io.fd.vpp + vppjapi + 1.0.0-SNAPSHOT + + + org.opendaylight.controller + sal-core-api + + + org.opendaylight.mdsal + mdsal-binding-dom-codec + + + + + ${project.groupId} + v3po-api + ${project.version} + test + + + junit + junit + test + + + org.mockito + mockito-all + test + + + + + diff --git a/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/util/DelegatingReaderRegistry.java b/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/util/DelegatingReaderRegistry.java new file mode 100644 index 000000000..5217024e8 --- /dev/null +++ b/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/util/DelegatingReaderRegistry.java @@ -0,0 +1,113 @@ +/* + * 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.facade.impl.read.util; + +import static com.google.common.base.Preconditions.checkNotNull; + +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 io.fd.honeycomb.v3po.vpp.facade.impl.util.VppRWUtils; +import io.fd.honeycomb.v3po.vpp.facade.read.ListVppReader; +import io.fd.honeycomb.v3po.vpp.facade.read.ReadContext; +import io.fd.honeycomb.v3po.vpp.facade.read.ReadFailedException; +import io.fd.honeycomb.v3po.vpp.facade.read.ReaderRegistry; +import io.fd.honeycomb.v3po.vpp.facade.read.VppReader; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Simple reader registry able to perform and aggregated read (ROOT read) on top of all provided readers. Also able to + * delegate a specific read to one of the delegate readers. + * + * This could serve as a utility to hold & hide all available readers in upper layers. + */ +public final class DelegatingReaderRegistry implements ReaderRegistry { + + private static final Logger LOG = LoggerFactory.getLogger(DelegatingReaderRegistry.class); + + private final Map, VppReader> rootReaders; + + /** + * Create new {@link DelegatingReaderRegistry} + * + * @param rootReaders List of delegate readers + */ + public DelegatingReaderRegistry(@Nonnull final List> rootReaders) { + this.rootReaders = VppRWUtils.uniqueLinkedIndex(checkNotNull(rootReaders), VppRWUtils.MANAGER_CLASS_FUNCTION); + } + + @Override + @Nonnull + public Multimap, ? extends DataObject> readAll( + @Nonnull final ReadContext ctx) throws ReadFailedException { + + LOG.debug("Reading from all delegates: {}", this); + LOG.trace("Reading from all delegates: {}", rootReaders.values()); + + final Multimap, DataObject> objects = LinkedListMultimap.create(); + for (VppReader rootReader : rootReaders.values()) { + LOG.debug("Reading from delegate: {}", rootReader); + + if (rootReader instanceof ListVppReader) { + final List listEntries = + ((ListVppReader) rootReader).readList(rootReader.getManagedDataObjectType(), ctx); + if (!listEntries.isEmpty()) { + objects.putAll(rootReader.getManagedDataObjectType(), listEntries); + } + } else { + final Optional read = rootReader.read(rootReader.getManagedDataObjectType(), ctx); + if (read.isPresent()) { + objects.putAll(rootReader.getManagedDataObjectType(), Collections.singletonList(read.get())); + } + } + } + + return objects; + } + + @Nonnull + @Override + public Optional read(@Nonnull final InstanceIdentifier id, + @Nonnull final ReadContext ctx) + throws ReadFailedException { + final InstanceIdentifier.PathArgument first = checkNotNull( + Iterables.getFirst(id.getPathArguments(), null), "Empty id"); + final VppReader vppReader = rootReaders.get(first.getType()); + checkNotNull(vppReader, + "Unable to read %s. Missing reader. Current readers for: %s", id, rootReaders.keySet()); + LOG.debug("Reading from delegate: {}", vppReader); + return vppReader.read(id, ctx); + } + + /** + * @throws UnsupportedOperationException This getter is not supported for reader registry since it does not manage a + * specific node type + */ + @Nonnull + @Override + public InstanceIdentifier getManagedDataObjectType() { + throw new UnsupportedOperationException("Root registry has no type"); + } +} diff --git a/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/util/NoopReaderCustomizer.java b/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/util/NoopReaderCustomizer.java new file mode 100644 index 000000000..5b78cdbba --- /dev/null +++ b/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/util/NoopReaderCustomizer.java @@ -0,0 +1,32 @@ +/* + * 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.facade.impl.read.util; + +import io.fd.honeycomb.v3po.vpp.facade.Context; +import io.fd.honeycomb.v3po.vpp.facade.spi.read.RootVppReaderCustomizer; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public abstract class NoopReaderCustomizer> implements + RootVppReaderCustomizer { + + @Override + public void readCurrentAttributes(InstanceIdentifier id, final B builder, final Context context) { + // Noop + } +} diff --git a/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/util/ReflexiveChildReaderCustomizer.java b/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/util/ReflexiveChildReaderCustomizer.java new file mode 100644 index 000000000..a83269658 --- /dev/null +++ b/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/util/ReflexiveChildReaderCustomizer.java @@ -0,0 +1,57 @@ +/* + * 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.facade.impl.read.util; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import io.fd.honeycomb.v3po.vpp.facade.impl.util.ReflectionUtils; +import io.fd.honeycomb.v3po.vpp.facade.spi.read.ChildVppReaderCustomizer; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Collections; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; + +/** + * Might be slow ! + */ +public class ReflexiveChildReaderCustomizer> + extends ReflexiveRootReaderCustomizer + implements ChildVppReaderCustomizer { + + public ReflexiveChildReaderCustomizer(final Class builderClass) { + super(builderClass); + } + + // TODO Could be just a default implementation in interface (making this a mixin) + + @Override + public void merge(final Builder parentBuilder, final C readValue) { + final Optional method = + ReflectionUtils.findMethodReflex(parentBuilder.getClass(), "set", + Collections.>singletonList(readValue.getClass()), parentBuilder.getClass()); + + Preconditions.checkArgument(method.isPresent(), "Unable to set %s to %s", readValue, parentBuilder); + + try { + method.get().invoke(parentBuilder, readValue); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new IllegalArgumentException("Unable to set " + readValue + " to " + parentBuilder, e); + } + } + +} diff --git a/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/util/ReflexiveRootReaderCustomizer.java b/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/util/ReflexiveRootReaderCustomizer.java new file mode 100644 index 000000000..b78bcdc06 --- /dev/null +++ b/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/read/util/ReflexiveRootReaderCustomizer.java @@ -0,0 +1,42 @@ +/* + * 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.facade.impl.read.util; + +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Might be slow ! + */ +public class ReflexiveRootReaderCustomizer> extends NoopReaderCustomizer { + + private final Class builderClass; + + public ReflexiveRootReaderCustomizer(final Class builderClass) { + this.builderClass = builderClass; + } + + @Override + public B getBuilder(InstanceIdentifier id) { + try { + return builderClass.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new IllegalStateException("Unable to instantiate " + builderClass, e); + } + } +} diff --git a/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/util/ReflectionUtils.java b/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/util/ReflectionUtils.java new file mode 100644 index 000000000..db560622c --- /dev/null +++ b/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/util/ReflectionUtils.java @@ -0,0 +1,79 @@ +/* + * 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.facade.impl.util; + +import com.google.common.base.Optional; +import java.lang.reflect.Method; +import java.util.List; +import javax.annotation.Nonnull; + +/** + * Reflection based utilities + */ +public final class ReflectionUtils { + + private ReflectionUtils() {} + + /** + * Find a specific method using reflection + * + * @param managedType Class object to find method in + * @param prefix Method name prefix used when finding the method. Case does not matter. + * @param paramTypes List of input argument types + * @param retType Return type + * + * @return Found method or Optional.absent() if there's no such method + */ + @Nonnull + public static Optional findMethodReflex(@Nonnull final Class managedType, + @Nonnull final String prefix, + @Nonnull final List> paramTypes, + @Nonnull final Class retType) { + for (Method method : managedType.getMethods()) { + if(isMethodMatch(prefix, paramTypes, retType, method)) { + return Optional.of(method); + } + } + + return Optional.absent(); + } + + private static boolean isMethodMatch(final @Nonnull String prefix, + final @Nonnull List> paramTypes, + final @Nonnull Class retType, final Method method) { + if (!method.getName().toLowerCase().startsWith(prefix.toLowerCase())) { + return false; + } + + final Class[] parameterTypes = method.getParameterTypes(); + if (parameterTypes.length != paramTypes.size()) { + return false; + } + + for (int i = 0; i < parameterTypes.length; i++) { + if (!parameterTypes[i].isAssignableFrom(paramTypes.get(i))) { + return false; + } + } + + if (!method.getReturnType().equals(retType)) { + return false; + } + + return true; + } +} diff --git a/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/util/VppApiCustomizer.java b/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/util/VppApiCustomizer.java new file mode 100644 index 000000000..41090f493 --- /dev/null +++ b/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/util/VppApiCustomizer.java @@ -0,0 +1,41 @@ +/* + * 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.facade.impl.util; + +import com.google.common.annotations.Beta; + +/** + * Abstract utility to hold the vppApi reference. + */ +@Beta +public abstract class VppApiCustomizer { + + private final org.openvpp.vppjapi.vppApi vppApi; + + protected VppApiCustomizer(final org.openvpp.vppjapi.vppApi vppApi) { + this.vppApi = vppApi; + } + + /** + * Get vppApi reference + * + * @return vppApi reference + */ + public org.openvpp.vppjapi.vppApi getVppApi() { + return vppApi; + } +} diff --git a/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/util/VppRWUtils.java b/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/util/VppRWUtils.java new file mode 100644 index 000000000..64667b85f --- /dev/null +++ b/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/util/VppRWUtils.java @@ -0,0 +1,178 @@ +/* + * 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.facade.impl.util; + +import com.google.common.base.Function; +import com.google.common.base.Preconditions; +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; +import com.google.common.collect.Maps; +import io.fd.honeycomb.v3po.vpp.facade.SubtreeManager; +import io.fd.honeycomb.v3po.vpp.facade.read.ChildVppReader; +import io.fd.honeycomb.v3po.vpp.facade.write.ChildVppWriter; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.Augmentation; +import org.opendaylight.yangtools.yang.binding.ChildOf; +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; + +public final class VppRWUtils { + + private VppRWUtils() {} + + /** + * Find next item in ID after provided type + */ + @Nonnull + public static InstanceIdentifier.PathArgument getNextId(@Nonnull final InstanceIdentifier id, + @Nonnull final InstanceIdentifier type) { + // TODO this is inefficient(maybe, depending on actual Iterable type) + final Iterable pathArguments = id.getPathArguments(); + final int i = Iterables.indexOf(pathArguments, new Predicate() { + @Override + public boolean apply(final InstanceIdentifier.PathArgument input) { + return input.getType().isAssignableFrom(type.getTargetType()); + } + }); + Preconditions.checkArgument(i >= 0, "Unable to find %s type in %s", type.getTargetType(), id); + return Iterables.get(pathArguments, i + 1); + } + + public static List>> emptyChildReaderList() { + return Collections.emptyList(); + } + + public static List>> emptyChildWriterList() { + return Collections.emptyList(); + } + + public static List>> emptyAugReaderList() { + return Collections.emptyList(); + } + + public static List>> emptyAugWriterList() { + return Collections.emptyList(); + } + + public static List>> singletonAugReaderList( + ChildVppReader> item) { + return Collections.>>singletonList(item); + } + + public static List>> singletonChildReaderList( + ChildVppReader> item) { + return Collections.>>singletonList(item); + } + + public static List>> singletonChildWriterList( + ChildVppWriter> item) { + return Collections.>>singletonList(item); + } + + /** + * Replace last item in ID with a provided IdentifiableItem of the same type + */ + @SuppressWarnings("unchecked") + @Nonnull + public static , K extends Identifier> InstanceIdentifier replaceLastInId( + @Nonnull final InstanceIdentifier id, final InstanceIdentifier.IdentifiableItem currentBdItem) { + + final Iterable pathArguments = id.getPathArguments(); + final Iterable withoutCurrent = + Iterables.limit(pathArguments, Iterables.size(pathArguments) - 1); + final Iterable concat = + Iterables.concat(withoutCurrent, Collections.singleton(currentBdItem)); + return (InstanceIdentifier) InstanceIdentifier.create(concat); + } + + /** + * Create IdentifiableItem from target type of provided ID with provided key + */ + @Nonnull + public static , K extends Identifier> InstanceIdentifier.IdentifiableItem getCurrentIdItem( + @Nonnull final InstanceIdentifier id, final K key) { + return new InstanceIdentifier.IdentifiableItem<>(id.getTargetType(), key); + } + + /** + * Trim InstanceIdentifier at indexOf(type) + */ + @SuppressWarnings("unchecked") + @Nonnull + public static InstanceIdentifier cutId(@Nonnull final InstanceIdentifier id, + @Nonnull final InstanceIdentifier type) { + final Iterable pathArguments = id.getPathArguments(); + final int i = Iterables.indexOf(pathArguments, new Predicate() { + @Override + public boolean apply(final InstanceIdentifier.PathArgument input) { + return input.getType().equals(type.getTargetType()); + } + }); + Preconditions.checkArgument(i >= 0, "ID %s does not contain %s", id, type); + return (InstanceIdentifier) InstanceIdentifier.create(Iterables.limit(pathArguments, i + 1)); + } + + /** + * Create a map from a collection, checking for duplicity in the process + */ + @Nonnull + public static Map uniqueLinkedIndex(@Nonnull final Collection values, @Nonnull final Function keyFunction) { + final Map objectObjectLinkedHashMap = Maps.newLinkedHashMap(); + for (V value : values) { + final K key = keyFunction.apply(value); + Preconditions.checkArgument(objectObjectLinkedHashMap.put(key, value) == null, + "Duplicate key detected : %s", key); + } + return objectObjectLinkedHashMap; + } + + public static final Function, Class> + MANAGER_CLASS_FUNCTION = new Function, Class>() { + @Override + public Class apply(final SubtreeManager input) { + return input.getManagedDataObjectType().getTargetType(); + } + }; + + public static final Function>, Class> + MANAGER_CLASS_AUG_FUNCTION = new Function>, Class>() { + + @Override + @SuppressWarnings("unchecked") + public Class apply(final SubtreeManager> input) { + final Class> targetType = input.getManagedDataObjectType().getTargetType(); + Preconditions.checkArgument(DataObject.class.isAssignableFrom(targetType)); + return (Class) targetType; + } + }; + + @SuppressWarnings("unchecked") + public static InstanceIdentifier appendTypeToId( + final InstanceIdentifier parentId, final InstanceIdentifier type) { + Preconditions.checkArgument(!parentId.contains(type), + "Unexpected InstanceIdentifier %s, already contains %s", parentId, type); + final InstanceIdentifier.PathArgument t = Iterables.getOnlyElement(type.getPathArguments()); + return (InstanceIdentifier) InstanceIdentifier.create(Iterables.concat( + parentId.getPathArguments(), Collections.singleton(t))); + } +} diff --git a/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/DelegatingWriterRegistry.java b/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/DelegatingWriterRegistry.java new file mode 100644 index 000000000..14cec7a55 --- /dev/null +++ b/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/DelegatingWriterRegistry.java @@ -0,0 +1,176 @@ +/* + * 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.facade.impl.write.util; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.base.Function; +import com.google.common.collect.Collections2; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import io.fd.honeycomb.v3po.vpp.facade.VppException; +import io.fd.honeycomb.v3po.vpp.facade.impl.util.VppRWUtils; +import io.fd.honeycomb.v3po.vpp.facade.write.VppWriter; +import io.fd.honeycomb.v3po.vpp.facade.write.WriteContext; +import io.fd.honeycomb.v3po.vpp.facade.write.WriterRegistry; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Simple writer registry able to perform and aggregated read (ROOT write) on top of all provided writers. Also able to + * delegate a specific read to one of the delegate writers. + * + * This could serve as a utility to hold & hide all available writers in upper layers. + */ +public final class DelegatingWriterRegistry implements WriterRegistry { + + private static final Logger LOG = LoggerFactory.getLogger(DelegatingWriterRegistry.class); + + private static final Function, Class> ID_TO_CLASS = + new Function, Class>() { + @Override + public Class apply(final InstanceIdentifier input) { + return input.getTargetType(); + } + }; + + private final Map, VppWriter> rootWriters; + + /** + * Create new {@link DelegatingWriterRegistry} + * + * @param rootWriters List of delegate writers + */ + public DelegatingWriterRegistry(@Nonnull final List> rootWriters) { + this.rootWriters = VppRWUtils.uniqueLinkedIndex(checkNotNull(rootWriters), VppRWUtils.MANAGER_CLASS_FUNCTION); + } + + /** + * @throws UnsupportedOperationException This getter is not supported for writer registry since it does not manage a + * specific node type + */ + @Nonnull + @Override + public InstanceIdentifier getManagedDataObjectType() { + throw new UnsupportedOperationException("Root registry has no type"); + } + + @Override + public void update(@Nonnull final InstanceIdentifier id, + @Nullable final DataObject dataBefore, + @Nullable final DataObject dataAfter, + @Nonnull final WriteContext ctx) throws VppException { + final InstanceIdentifier.PathArgument first = checkNotNull( + Iterables.getFirst(id.getPathArguments(), null), "Empty id"); + final VppWriter vppWriter = rootWriters.get(first.getType()); + checkNotNull(vppWriter, + "Unable to write %s. Missing writer. Current writers for: %s", id, rootWriters.keySet()); + vppWriter.update(id, dataBefore, dataAfter, ctx); + } + + @Override + public void update(@Nonnull final Map, DataObject> nodesBefore, + @Nonnull final Map, DataObject> nodesAfter, + @Nonnull final WriteContext ctx) throws VppException { + checkAllWritersPresent(nodesBefore); + checkAllWritersPresent(nodesAfter); + + final List> processedNodes = Lists.newArrayList(); + + for (Map.Entry, VppWriter> rootWriterEntry : rootWriters + .entrySet()) { + + final InstanceIdentifier id = rootWriterEntry.getValue().getManagedDataObjectType(); + + final DataObject dataBefore = nodesBefore.get(id); + final DataObject dataAfter = nodesAfter.get(id); + + // No change to current writer + if (dataBefore == null && dataAfter == null) { + continue; + } + + LOG.debug("ChangesProcessor.applyChanges() processing dataBefore={}, dataAfter={}", dataBefore, dataAfter); + + try { + update(id, dataBefore, dataAfter, ctx); + processedNodes.add(id); + } catch (Exception e) { + LOG.error("Error while processing data change of: {} (before={}, after={})", + id, dataBefore, dataAfter, e); + throw new BulkUpdateException( + id, new ReverterImpl(this, processedNodes, nodesBefore, nodesAfter, ctx), e); + } + } + } + + private void checkAllWritersPresent(final @Nonnull Map, DataObject> nodesBefore) { + checkArgument(rootWriters.keySet().containsAll(Collections2.transform(nodesBefore.keySet(), ID_TO_CLASS)), + "Unable to handle all changes. Missing dedicated writers for: %s", + Sets.difference(nodesBefore.keySet(), rootWriters.keySet())); + } + + private static final class ReverterImpl implements Reverter { + private final WriterRegistry delegatingWriterRegistry; + private final List> processedNodes; + private final Map, DataObject> nodesBefore; + private final Map, DataObject> nodesAfter; + private final WriteContext ctx; + + ReverterImpl(final WriterRegistry delegatingWriterRegistry, + final List> processedNodes, + final Map, DataObject> nodesBefore, + final Map, DataObject> nodesAfter, final WriteContext ctx) { + this.delegatingWriterRegistry = delegatingWriterRegistry; + this.processedNodes = processedNodes; + this.nodesBefore = nodesBefore; + this.nodesAfter = nodesAfter; + this.ctx = ctx; + } + + @Override + public void revert() throws RevertFailedException { + final LinkedList> notReverted = new LinkedList<>(processedNodes); + + while (notReverted.size() > 0) { + final InstanceIdentifier node = notReverted.peekLast(); + LOG.debug("ChangesProcessor.revertChanges() processing node={}", node); + + final DataObject dataBefore = nodesBefore.get(node); + final DataObject dataAfter = nodesAfter.get(node); + + // revert a change by invoking writer with reordered arguments + try { + delegatingWriterRegistry.update(node, dataAfter, dataBefore, ctx); + notReverted.removeLast(); // change was successfully reverted + } catch (Exception e) { + throw new RevertFailedException(notReverted, e); + } + + } + } + } +} diff --git a/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/NoopWriterCustomizer.java b/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/NoopWriterCustomizer.java new file mode 100644 index 000000000..96b7d19b4 --- /dev/null +++ b/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/NoopWriterCustomizer.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.vpp.facade.impl.write.util; + +import io.fd.honeycomb.v3po.vpp.facade.Context; +import io.fd.honeycomb.v3po.vpp.facade.spi.write.RootVppWriterCustomizer; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Customizer not performing any changes on current level. Suitable for nodes that don't have any leaves and all of + * its child nodes are managed by dedicated writers + */ +public class NoopWriterCustomizer implements RootVppWriterCustomizer { + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D dataAfter, + @Nonnull final Context ctx) { + + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D dataBefore, + @Nonnull final D dataAfter, + @Nonnull final Context ctx) { + + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final D dataBefore, + @Nonnull final Context ctx) { + + } +} diff --git a/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/ReflexiveChildWriterCustomizer.java b/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/ReflexiveChildWriterCustomizer.java new file mode 100644 index 000000000..820f469d6 --- /dev/null +++ b/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/ReflexiveChildWriterCustomizer.java @@ -0,0 +1,59 @@ +/* + * 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.facade.impl.write.util; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.collect.Iterables; +import io.fd.honeycomb.v3po.vpp.facade.impl.util.ReflectionUtils; +import io.fd.honeycomb.v3po.vpp.facade.spi.write.ChildVppWriterCustomizer; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Collections; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Might be slow ! + */ +public class ReflexiveChildWriterCustomizer extends NoopWriterCustomizer implements + ChildVppWriterCustomizer { + + @Nonnull + @Override + @SuppressWarnings("unchecked") + public Optional extract(@Nonnull final InstanceIdentifier currentId, @Nonnull final DataObject parentData) { + final Class currentType = currentId.getTargetType(); + final Optional method = ReflectionUtils.findMethodReflex(getParentType(currentId), + "get" + currentType.getSimpleName(), Collections.>emptyList(), currentType); + + Preconditions.checkArgument(method.isPresent(), "Unable to get %s from %s", currentType, parentData); + + try { + return method.isPresent() + ? Optional.of((C) method.get().invoke(parentData)) + : Optional.absent(); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new IllegalArgumentException("Unable to get " + currentType + " from " + parentData, e); + } + } + + private Class getParentType(final @Nonnull InstanceIdentifier currentId) { + return Iterables.get(currentId.getPathArguments(), Iterables.size(currentId.getPathArguments()) - 2).getType(); + } +} diff --git a/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/TransactionWriteContext.java b/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/TransactionWriteContext.java new file mode 100644 index 000000000..da124b03c --- /dev/null +++ b/v3po/vpp-facade-utils/src/main/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/TransactionWriteContext.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.vpp.facade.impl.write.util; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; +import io.fd.honeycomb.v3po.vpp.facade.Context; +import io.fd.honeycomb.v3po.vpp.facade.write.WriteContext; +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.ReadFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; +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.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +/** + * Transaction based WriteContext + */ +public final class TransactionWriteContext implements WriteContext { + + private final DOMDataReadOnlyTransaction beforeTx; + private final DOMDataReadOnlyTransaction afterTx; + private final Context ctx; + private final BindingNormalizedNodeSerializer serializer; + + public TransactionWriteContext(final BindingNormalizedNodeSerializer serializer, + final DOMDataReadOnlyTransaction beforeTx, + final DOMDataReadOnlyTransaction afterTx) { + this.serializer = serializer; + this.beforeTx = beforeTx; + this.afterTx = afterTx; + this.ctx = new Context(); + } + + // TODO make this asynchronous + + @Override + public Optional readBefore(@Nonnull final InstanceIdentifier currentId) { + return read(currentId, beforeTx); + } + + private Optional read(final InstanceIdentifier currentId, + final DOMDataReadOnlyTransaction tx) { + final YangInstanceIdentifier path = serializer.toYangInstanceIdentifier(currentId); + + final CheckedFuture>, ReadFailedException> read = + tx.read(LogicalDatastoreType.CONFIGURATION, path); + + try { + // TODO once the APIs are asynchronous use just Futures.transform + final Optional> optional = read.checkedGet(); + + if (!optional.isPresent()) { + return Optional.absent(); + } + + final NormalizedNode data = optional.get(); + final Map.Entry, DataObject> entry = serializer.fromNormalizedNode(path, data); + + return Optional.of(entry.getValue()); + } catch (ReadFailedException e) { + throw new IllegalStateException("Unable to perform read", e); + } + } + + @Override + public Optional readAfter(@Nonnull final InstanceIdentifier currentId) { + return read(currentId, afterTx); + } + + @Override + public Context getContext() { + return ctx; + } + + /** + * Does not close the transactions + */ + @Override + public void close() { + ctx.close(); + } +} diff --git a/v3po/vpp-facade-utils/src/test/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/DelegatingWriterRegistryTest.java b/v3po/vpp-facade-utils/src/test/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/DelegatingWriterRegistryTest.java new file mode 100644 index 000000000..774974d4f --- /dev/null +++ b/v3po/vpp-facade-utils/src/test/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/DelegatingWriterRegistryTest.java @@ -0,0 +1,188 @@ +/* + * 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.facade.impl.write.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import io.fd.honeycomb.v3po.vpp.facade.VppException; +import io.fd.honeycomb.v3po.vpp.facade.write.VppWriter; +import io.fd.honeycomb.v3po.vpp.facade.write.WriteContext; +import io.fd.honeycomb.v3po.vpp.facade.write.WriterRegistry; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class DelegatingWriterRegistryTest { + + private final InstanceIdentifier vppId; + private final InstanceIdentifier vppStateId; + private final InstanceIdentifier interfaceId; + + private WriteContext ctx; + private VppWriter vppWriter; + private VppWriter vppStateWriter; + private VppWriter interfacesWriter; + + private DelegatingWriterRegistry registry; + + public DelegatingWriterRegistryTest() { + vppId = InstanceIdentifier.create(Vpp.class); + vppStateId = InstanceIdentifier.create(VppState.class); + interfaceId = InstanceIdentifier.create(Interfaces.class); + } + + @SuppressWarnings("unchecked") + private VppWriter mockWriter(Class clazz) { + final VppWriter mock = (VppWriter) Mockito.mock(VppWriter.class); + doReturn(InstanceIdentifier.create(clazz)).when(mock).getManagedDataObjectType(); + return mock; + } + + private DataObject mockDataObject(final String name, final Class classToMock) { + final DataObject dataBefore = mock(classToMock, name); + doReturn(classToMock).when(dataBefore).getImplementedInterface(); + return dataBefore; + } + + @SuppressWarnings("unchecked") + private static Map, DataObject> asMap(DataObject... objects) { + final Map, DataObject> map = new HashMap<>(); + for (DataObject object : objects) { + final Class implementedInterface = + (Class) object.getImplementedInterface(); + final InstanceIdentifier id = InstanceIdentifier.create(implementedInterface); + map.put(id, object); + } + return map; + } + + @Before + public void setUp() { + ctx = mock(WriteContext.class); + vppWriter = mockWriter(Vpp.class); + vppStateWriter = mockWriter(VppState.class); + interfacesWriter = mockWriter(Interfaces.class); + + final List> writers = new ArrayList<>(); + writers.add(vppWriter); + writers.add(vppStateWriter); + writers.add(interfacesWriter); + + registry = new DelegatingWriterRegistry(writers); + } + + @Test(expected = UnsupportedOperationException.class) + public void testGetManagedDataObjectType() { + registry.getManagedDataObjectType(); + } + + @Test + public void testBulkUpdateRevert() throws Exception { + // Prepare data changes: + final DataObject dataBefore1 = mockDataObject("Vpp before", Vpp.class); + final DataObject dataAfter1 = mockDataObject("Vpp after", Vpp.class); + + final DataObject dataBefore2 = mockDataObject("VppState before", VppState.class); + final DataObject dataAfter2 = mockDataObject("VppState after", VppState.class); + + // Fail on update + doThrow(new VppException("vpp failed")).when(vppStateWriter) + .update(vppStateId, dataBefore2, dataAfter2, ctx); + + // Run the test + try { + registry.update(asMap(dataBefore1, dataBefore2), asMap(dataAfter1, dataAfter2), ctx); + } catch (WriterRegistry.BulkUpdateException e) { + // Check second update failed + assertEquals(vppStateId, e.getFailedId()); + verify(vppWriter).update(vppId, dataBefore1, dataAfter1, ctx); + verify(vppStateWriter).update(vppStateId, dataBefore2, dataAfter2, ctx); + + // Try to revert changes + e.revertChanges(); + + // Check revert was successful + verify(vppWriter).update(vppId, dataAfter1, dataBefore1, ctx); + verify(vppStateWriter, never()).update(vppStateId, dataAfter2, dataBefore2, ctx); + + return; + } + fail("BulkUpdateException expected"); + } + + @Test + public void testBulkUpdateRevertFail() throws Exception { + // Prepare data changes: + final DataObject dataBefore1 = mockDataObject("Vpp before", Vpp.class); + final DataObject dataAfter1 = mockDataObject("Vpp after", Vpp.class); + + final DataObject dataBefore2 = mockDataObject("VppState before", VppState.class); + final DataObject dataAfter2 = mockDataObject("VppState after", VppState.class); + + final DataObject dataBefore3 = mockDataObject("Interfaces before", Interfaces.class); + final DataObject dataAfter3 = mockDataObject("Interfaces after", Interfaces.class); + + // Fail on the third update + doThrow(new VppException("vpp failed")).when(interfacesWriter) + .update(interfaceId, dataBefore3, dataAfter3, ctx); + + // Fail on the second revert + doThrow(new VppException("vpp failed again")).when(vppWriter) + .update(vppId, dataAfter1, dataBefore1, ctx); + + // Run the test + try { + registry.update(asMap(dataBefore1, dataBefore2, dataBefore3), asMap(dataAfter1, dataAfter2, dataAfter3), ctx); + } catch (WriterRegistry.BulkUpdateException e) { + // Check third update failed + assertEquals(interfaceId, e.getFailedId()); + verify(vppWriter).update(vppId, dataBefore1, dataAfter1, ctx); + verify(vppStateWriter).update(vppStateId, dataBefore2, dataAfter2, ctx); + verify(interfacesWriter).update(interfaceId, dataBefore3, dataAfter3, ctx); + + // Try to revert changes + try { + e.revertChanges(); + } catch (WriterRegistry.Reverter.RevertFailedException e2) { + // Check second revert failed + assertEquals(Collections.singletonList(vppId), e2.getNotRevertedChanges()); + verify(vppWriter).update(vppId, dataAfter1, dataBefore1, ctx); + verify(vppStateWriter).update(vppStateId, dataAfter2, dataBefore2, ctx); + verify(interfacesWriter, never()).update(interfaceId, dataAfter3, dataBefore3, ctx); + return; + } + fail("WriterRegistry.Revert.RevertFailedException expected"); + } + fail("BulkUpdateException expected"); + } +} \ No newline at end of file diff --git a/v3po/vpp-facade-utils/src/test/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/TransactionWriteContextTest.java b/v3po/vpp-facade-utils/src/test/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/TransactionWriteContextTest.java new file mode 100644 index 000000000..0e46e2fa4 --- /dev/null +++ b/v3po/vpp-facade-utils/src/test/java/io/fd/honeycomb/v3po/vpp/facade/impl/write/util/TransactionWriteContextTest.java @@ -0,0 +1,138 @@ +/* + * 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.facade.impl.write.util; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +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.vpp.facade.Context; +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.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; +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 TransactionWriteContextTest { + + @Mock + private BindingNormalizedNodeSerializer serializer; + @Mock + private DOMDataReadOnlyTransaction beforeTx; + @Mock + private DOMDataReadOnlyTransaction afterTx; + @Mock + private CheckedFuture>, ReadFailedException> future; + @Mock + private Optional> optional; + @Mock + private Map.Entry entry; + + private TransactionWriteContext transactionWriteContext; + + @Before + public void setUp() { + initMocks(this); + transactionWriteContext = new TransactionWriteContext(serializer, beforeTx, afterTx); + } + + @Test + public void testReadBeforeNoData() throws Exception { + when(beforeTx.read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn(future); + when(future.checkedGet()).thenReturn(optional); + when(optional.isPresent()).thenReturn(false); + + final InstanceIdentifier instanceId = + InstanceIdentifier.create(Vpp.class).child(BridgeDomains.class).child(BridgeDomain.class); + + final Optional dataObjects = transactionWriteContext.readBefore(instanceId); + assertNotNull(dataObjects); + assertFalse(dataObjects.isPresent()); + + verify(serializer).toYangInstanceIdentifier(instanceId); + verify(serializer, never()).fromNormalizedNode(any(YangInstanceIdentifier.class), any(NormalizedNode.class)); + } + + + @Test + public void testReadBefore() throws Exception { + when(beforeTx.read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn(future); + when(future.checkedGet()).thenReturn(optional); + when(optional.isPresent()).thenReturn(true); + + final InstanceIdentifier instanceId = + InstanceIdentifier.create(Vpp.class).child(BridgeDomains.class).child(BridgeDomain.class); + final YangInstanceIdentifier yangId = YangInstanceIdentifier.builder().node(VppState.QNAME).node( + BridgeDomains.QNAME).node(BridgeDomain.QNAME).build(); + when(serializer.toYangInstanceIdentifier(any(InstanceIdentifier.class))).thenReturn(yangId); + when(serializer.fromNormalizedNode(eq(yangId), any(NormalizedNode.class))).thenReturn(entry); + when(entry.getValue()).thenReturn(mock(DataObject.class)); + + final Optional dataObjects = transactionWriteContext.readBefore(instanceId); + assertNotNull(dataObjects); + assertTrue(dataObjects.isPresent()); + + verify(serializer).toYangInstanceIdentifier(instanceId); + verify(serializer).fromNormalizedNode(eq(yangId), any(NormalizedNode.class)); + } + + @Test(expected = IllegalStateException.class) + public void testReadBeforeFailed() throws Exception { + when(beforeTx.read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn(future); + when(future.checkedGet()).thenThrow(ReadFailedException.class); + transactionWriteContext.readBefore(mock(InstanceIdentifier.class)); + } + + @Test(expected = IllegalStateException.class) + public void testReadAfterFailed() throws Exception { + when(afterTx.read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn(future); + when(future.checkedGet()).thenThrow(ReadFailedException.class); + transactionWriteContext.readAfter(mock(InstanceIdentifier.class)); + } + + @Test + public void testGetContext() throws Exception { + assertNotNull(transactionWriteContext.getContext()); + } + + @Test + public void testClose() throws Exception { + final Context context = transactionWriteContext.getContext(); + transactionWriteContext.close(); + // TODO verify context was closed + } +} \ No newline at end of file -- cgit 1.2.3-korg