From c3661fb2793928359ef28c4439a67d3208ff1604 Mon Sep 17 00:00:00 2001 From: Maros Marsalek Date: Tue, 12 Apr 2016 10:13:21 +0200 Subject: HONEYCOMB-8: Move data layer from impl module into submodules Change-Id: Ic75793f65cfcad7cc2c96e7a09093e0e1802e4e5 Signed-off-by: Marek Gradzki Signed-off-by: Maros Marsalek --- v3po/artifacts/pom.xml | 15 ++ v3po/config/pom.xml | 31 +++ .../fd/honeycomb/v3po/config/ReaderRegistry.java | 116 +++++++++ .../fd/honeycomb/v3po/config/WriterRegistry.java | 104 ++++++++ v3po/data-api/pom.xml | 40 +++ .../honeycomb/v3po/data/ReadableVppDataTree.java | 39 +++ .../io/fd/honeycomb/v3po/data/VppDataTree.java | 44 ++++ .../honeycomb/v3po/data/VppDataTreeSnapshot.java | 34 +++ v3po/data-impl/pom.xml | 86 +++++++ .../fd/honeycomb/v3po/data/impl/DataTreeUtils.java | 76 ++++++ .../v3po/data/impl/ReadWriteTransaction.java | 101 ++++++++ .../v3po/data/impl/VppConfigDataTree.java | 172 +++++++++++++ .../fd/honeycomb/v3po/data/impl/VppDataBroker.java | 98 +++++++ .../v3po/data/impl/VppOperationalDataTree.java | 210 +++++++++++++++ .../v3po/data/impl/VppReadOnlyTransaction.java | 105 ++++++++ .../v3po/data/impl/VppWriteTransaction.java | 147 +++++++++++ .../v3po/data/impl/DataTreeUtilsTest.java | 68 +++++ .../v3po/data/impl/ReadWriteTransactionTest.java | 111 ++++++++ .../v3po/data/impl/VPPConfigDataTreeTest.java | 270 ++++++++++++++++++++ .../v3po/data/impl/VppDataBrokerTest.java | 111 ++++++++ .../v3po/data/impl/VppOperationalDataTreeTest.java | 171 +++++++++++++ .../v3po/data/impl/VppReadOnlyTransactionTest.java | 68 +++++ .../v3po/data/impl/VppWriteTransactionTest.java | 136 ++++++++++ v3po/features/pom.xml | 15 ++ v3po/features/src/main/features/features.xml | 3 + v3po/impl/pom.xml | 10 + .../io/fd/honeycomb/v3po/impl/V3poProvider.java | 5 +- .../impl/VppDataBrokerInitializationProvider.java | 282 +++++++++++++++++++++ .../fd/honeycomb/v3po/impl/data/DataTreeUtils.java | 76 ------ .../v3po/impl/data/ReadWriteTransaction.java | 101 -------- .../v3po/impl/data/ReadableVppDataTree.java | 39 --- .../honeycomb/v3po/impl/data/ReaderRegistry.java | 116 --------- .../v3po/impl/data/VppConfigDataTree.java | 167 ------------ .../fd/honeycomb/v3po/impl/data/VppDataBroker.java | 95 ------- .../data/VppDataBrokerInitializationProvider.java | 277 -------------------- .../fd/honeycomb/v3po/impl/data/VppDataTree.java | 44 ---- .../v3po/impl/data/VppDataTreeSnapshot.java | 34 --- .../v3po/impl/data/VppOperationalDataTree.java | 209 --------------- .../v3po/impl/data/VppReadOnlyTransaction.java | 103 -------- .../v3po/impl/data/VppWriteTransaction.java | 145 ----------- .../honeycomb/v3po/impl/data/WriterRegistry.java | 104 -------- .../v3po/impl/data/DataTreeUtilsTest.java | 72 ------ .../v3po/impl/data/ReadWriteTransactionTest.java | 111 -------- .../v3po/impl/data/VPPConfigDataTreeTest.java | 268 -------------------- .../VppDataBrokerInitializationProviderTest.java | 2 + .../v3po/impl/data/VppDataBrokerTest.java | 108 -------- .../v3po/impl/data/VppOperationalDataTreeTest.java | 171 ------------- .../v3po/impl/data/VppReadOnlyTransactionTest.java | 66 ----- .../v3po/impl/data/VppWriteTransactionTest.java | 134 ---------- v3po/pom.xml | 3 + 50 files changed, 2670 insertions(+), 2443 deletions(-) create mode 100644 v3po/config/pom.xml create mode 100644 v3po/config/src/main/java/io/fd/honeycomb/v3po/config/ReaderRegistry.java create mode 100644 v3po/config/src/main/java/io/fd/honeycomb/v3po/config/WriterRegistry.java create mode 100644 v3po/data-api/pom.xml create mode 100644 v3po/data-api/src/main/java/io/fd/honeycomb/v3po/data/ReadableVppDataTree.java create mode 100644 v3po/data-api/src/main/java/io/fd/honeycomb/v3po/data/VppDataTree.java create mode 100644 v3po/data-api/src/main/java/io/fd/honeycomb/v3po/data/VppDataTreeSnapshot.java create mode 100644 v3po/data-impl/pom.xml create mode 100644 v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataTreeUtils.java create mode 100644 v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadWriteTransaction.java create mode 100644 v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppConfigDataTree.java create mode 100644 v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppDataBroker.java create mode 100644 v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppOperationalDataTree.java create mode 100644 v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppReadOnlyTransaction.java create mode 100644 v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppWriteTransaction.java create mode 100644 v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/DataTreeUtilsTest.java create mode 100644 v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadWriteTransactionTest.java create mode 100644 v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VPPConfigDataTreeTest.java create mode 100644 v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppDataBrokerTest.java create mode 100644 v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppOperationalDataTreeTest.java create mode 100644 v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppReadOnlyTransactionTest.java create mode 100644 v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppWriteTransactionTest.java create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppDataBrokerInitializationProvider.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/DataTreeUtils.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/ReadWriteTransaction.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/ReadableVppDataTree.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/ReaderRegistry.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppConfigDataTree.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataBroker.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerInitializationProvider.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataTree.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataTreeSnapshot.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppOperationalDataTree.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppReadOnlyTransaction.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppWriteTransaction.java delete mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/WriterRegistry.java delete mode 100644 v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/DataTreeUtilsTest.java delete mode 100644 v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/ReadWriteTransactionTest.java delete mode 100644 v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VPPConfigDataTreeTest.java delete mode 100644 v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerTest.java delete mode 100644 v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppOperationalDataTreeTest.java delete mode 100644 v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppReadOnlyTransactionTest.java delete mode 100644 v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppWriteTransactionTest.java (limited to 'v3po') diff --git a/v3po/artifacts/pom.xml b/v3po/artifacts/pom.xml index 1764b675f..9240da571 100644 --- a/v3po/artifacts/pom.xml +++ b/v3po/artifacts/pom.xml @@ -29,6 +29,21 @@ v3po-api ${project.version} + + ${project.groupId} + data-api + ${project.version} + + + ${project.groupId} + data-utils + ${project.version} + + + ${project.groupId} + data-impl + ${project.version} + ${project.groupId} translate-api diff --git a/v3po/config/pom.xml b/v3po/config/pom.xml new file mode 100644 index 000000000..910fc7daa --- /dev/null +++ b/v3po/config/pom.xml @@ -0,0 +1,31 @@ + + + + io.fd.honeycomb.common + api-parent + 1.0.0-SNAPSHOT + ../../common/api-parent + + + 4.0.0 + io.fd.honeycomb.v3po + config + 1.0.0-SNAPSHOT + bundle + + + + io.fd.honeycomb.v3po + translate-impl + ${project.version} + + + io.fd.honeycomb.v3po + v3po2vpp + ${project.version} + + + + \ No newline at end of file diff --git a/v3po/config/src/main/java/io/fd/honeycomb/v3po/config/ReaderRegistry.java b/v3po/config/src/main/java/io/fd/honeycomb/v3po/config/ReaderRegistry.java new file mode 100644 index 000000000..7ab2dd430 --- /dev/null +++ b/v3po/config/src/main/java/io/fd/honeycomb/v3po/config/ReaderRegistry.java @@ -0,0 +1,116 @@ +/* + * 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.config; + +import com.google.common.base.Optional; +import com.google.common.collect.Multimap; +import io.fd.honeycomb.v3po.translate.impl.read.CompositeChildReader; +import io.fd.honeycomb.v3po.translate.impl.read.CompositeListReader; +import io.fd.honeycomb.v3po.translate.impl.read.CompositeRootReader; +import io.fd.honeycomb.v3po.translate.util.read.DelegatingReaderRegistry; +import io.fd.honeycomb.v3po.translate.util.read.ReflexiveChildReaderCustomizer; +import io.fd.honeycomb.v3po.translate.util.read.ReflexiveRootReaderCustomizer; +import io.fd.honeycomb.v3po.translate.util.RWUtils; +import io.fd.honeycomb.v3po.translate.read.ChildReader; +import io.fd.honeycomb.v3po.translate.read.ReadContext; +import io.fd.honeycomb.v3po.translate.read.ReadFailedException; +import io.fd.honeycomb.v3po.translate.read.Reader; +import io.fd.honeycomb.v3po.translate.v3po.vppstate.BridgeDomainCustomizer; +import io.fd.honeycomb.v3po.translate.v3po.vppstate.VersionCustomizer; +import java.util.ArrayList; +import java.util.Collections; +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.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.vppjapi.vppApi; + +// TODO use some DI framework instead of singleton +public class ReaderRegistry implements io.fd.honeycomb.v3po.translate.read.ReaderRegistry { + + private static ReaderRegistry instance; + + private final DelegatingReaderRegistry reader; + + private ReaderRegistry(@Nonnull final vppApi vppApi) { + final CompositeRootReader vppStateReader = initVppStateReader(vppApi); + // TODO add more root readers + reader = new DelegatingReaderRegistry(Collections.>singletonList(vppStateReader)); + } + + private static CompositeRootReader initVppStateReader(@Nonnull final vppApi vppApi) { + + final ChildReader versionReader = new CompositeChildReader<>( + Version.class, new VersionCustomizer(vppApi)); + + final CompositeListReader + bridgeDomainReader = new CompositeListReader<>( + BridgeDomain.class, + new BridgeDomainCustomizer(vppApi)); + + final ChildReader bridgeDomainsReader = new CompositeChildReader<>( + BridgeDomains.class, + RWUtils.singletonChildReaderList(bridgeDomainReader), + new ReflexiveChildReaderCustomizer<>(BridgeDomainsBuilder.class)); + + final List>> childVppReaders = new ArrayList<>(); + childVppReaders.add(versionReader); + childVppReaders.add(bridgeDomainsReader); + + return new CompositeRootReader<>( + VppState.class, + childVppReaders, + RWUtils.emptyAugReaderList(), + new ReflexiveRootReaderCustomizer<>(VppStateBuilder.class)); + } + + public static synchronized ReaderRegistry getInstance(@Nonnull final vppApi vppApi) { + if (instance == null) { + instance = new ReaderRegistry(vppApi); + } + return instance; + } + + @Nonnull + @Override + public Multimap, ? extends DataObject> readAll( + @Nonnull final ReadContext ctx) throws ReadFailedException { + return reader.readAll(ctx); + } + + @Nonnull + @Override + public Optional read(@Nonnull final InstanceIdentifier id, + @Nonnull final ReadContext ctx) throws ReadFailedException { + return reader.read(id, ctx); + } + + @Nonnull + @Override + public InstanceIdentifier getManagedDataObjectType() { + return reader.getManagedDataObjectType(); + } +} diff --git a/v3po/config/src/main/java/io/fd/honeycomb/v3po/config/WriterRegistry.java b/v3po/config/src/main/java/io/fd/honeycomb/v3po/config/WriterRegistry.java new file mode 100644 index 000000000..2d579c449 --- /dev/null +++ b/v3po/config/src/main/java/io/fd/honeycomb/v3po/config/WriterRegistry.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.config; + +import io.fd.honeycomb.v3po.translate.TranslationException; +import io.fd.honeycomb.v3po.translate.util.RWUtils; +import io.fd.honeycomb.v3po.translate.impl.write.CompositeChildWriter; +import io.fd.honeycomb.v3po.translate.impl.write.CompositeListWriter; +import io.fd.honeycomb.v3po.translate.impl.write.CompositeRootWriter; +import io.fd.honeycomb.v3po.translate.util.write.DelegatingWriterRegistry; +import io.fd.honeycomb.v3po.translate.util.write.NoopWriterCustomizer; +import io.fd.honeycomb.v3po.translate.util.write.ReflexiveChildWriterCustomizer; +import io.fd.honeycomb.v3po.translate.v3po.vpp.BridgeDomainCustomizer; +import io.fd.honeycomb.v3po.translate.write.ChildWriter; +import io.fd.honeycomb.v3po.translate.write.Writer; +import io.fd.honeycomb.v3po.translate.write.WriteContext; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +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.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.vppjapi.vppApi; + +// TODO use some DI framework instead of singleton +public class WriterRegistry implements io.fd.honeycomb.v3po.translate.write.WriterRegistry { + + private static WriterRegistry instance; + + private final DelegatingWriterRegistry writer; + + private WriterRegistry(@Nonnull final vppApi vppApi) { + final CompositeRootWriter vppWriter = initVppStateWriter(vppApi); + writer = new DelegatingWriterRegistry(Collections.>singletonList(vppWriter)); + } + + private static CompositeRootWriter initVppStateWriter(@Nonnull final vppApi vppApi) { + final CompositeListWriter bridgeDomainWriter = new CompositeListWriter<>( + BridgeDomain.class, + new BridgeDomainCustomizer(vppApi)); + + final ChildWriter bridgeDomainsWriter = new CompositeChildWriter<>( + BridgeDomains.class, + RWUtils.singletonChildWriterList(bridgeDomainWriter), + new ReflexiveChildWriterCustomizer()); + + final List>> childWriters = new ArrayList<>(); + childWriters.add(bridgeDomainsWriter); + + return new CompositeRootWriter<>( + Vpp.class, + childWriters, + new NoopWriterCustomizer()); + } + + public static synchronized WriterRegistry getInstance(@Nonnull final vppApi vppApi) { + if (instance == null) { + instance = new WriterRegistry(vppApi); + } + return instance; + } + + @Nonnull + @Override + public InstanceIdentifier getManagedDataObjectType() { + return writer.getManagedDataObjectType(); + } + + @Override + public void update(@Nonnull final InstanceIdentifier id, + @Nullable final DataObject dataBefore, + @Nullable final DataObject data, @Nonnull final WriteContext ctx) throws TranslationException { + writer.update(id, dataBefore, data, ctx); + } + + @Override + public void update(@Nonnull final Map, DataObject> dataBefore, + @Nonnull final Map, DataObject> dataAfter, + @Nonnull final WriteContext ctx) + throws TranslationException { + writer.update(dataBefore, dataAfter, ctx); + } +} diff --git a/v3po/data-api/pom.xml b/v3po/data-api/pom.xml new file mode 100644 index 000000000..88be38d9f --- /dev/null +++ b/v3po/data-api/pom.xml @@ -0,0 +1,40 @@ + + + + io.fd.honeycomb.common + api-parent + 1.0.0-SNAPSHOT + ../../common/api-parent + + + 4.0.0 + io.fd.honeycomb.v3po + data-api + 1.0.0-SNAPSHOT + bundle + + + + io.fd.honeycomb.v3po + translate-api + ${project.version} + + + com.google.guava + guava + + + org.opendaylight.yangtools + yang-data-api + + + org.opendaylight.controller + sal-common-api + 1.3.0-Beryllium + + + + + \ No newline at end of file diff --git a/v3po/data-api/src/main/java/io/fd/honeycomb/v3po/data/ReadableVppDataTree.java b/v3po/data-api/src/main/java/io/fd/honeycomb/v3po/data/ReadableVppDataTree.java new file mode 100644 index 000000000..22a52aa41 --- /dev/null +++ b/v3po/data-api/src/main/java/io/fd/honeycomb/v3po/data/ReadableVppDataTree.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.data; + +import com.google.common.annotations.Beta; +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; +import javax.annotation.Nonnull; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +/** + * Facade over VPP data tree that allows reading tree nodes. + */ +@Beta +public interface ReadableVppDataTree { + /** + * Reads a particular node from the VPP data tree. + * + * @param path Path of the node + * @return a CheckFuture containing the result of the read. + */ + CheckedFuture>, ReadFailedException> read(@Nonnull final YangInstanceIdentifier path); +} diff --git a/v3po/data-api/src/main/java/io/fd/honeycomb/v3po/data/VppDataTree.java b/v3po/data-api/src/main/java/io/fd/honeycomb/v3po/data/VppDataTree.java new file mode 100644 index 000000000..dffd22d3a --- /dev/null +++ b/v3po/data-api/src/main/java/io/fd/honeycomb/v3po/data/VppDataTree.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.data; + +import com.google.common.annotations.Beta; +import io.fd.honeycomb.v3po.translate.TranslationException; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException; + +/** + * Facade over VPP data tree that allows tree modification. + */ +@Beta +public interface VppDataTree { + /** + * Commits modification to VPP data tree. + * + * @param modification VPP data tree modification + * @throws DataValidationFailedException if modification data is not valid + * @throws TranslationException if commit failed while updating VPP state + */ + void commit(final DataTreeModification modification) throws DataValidationFailedException, TranslationException; + + /** + * Creates read-only snapshot of a VppDataTree. + * + * @return Data tree snapshot. + */ + VppDataTreeSnapshot takeSnapshot(); +} diff --git a/v3po/data-api/src/main/java/io/fd/honeycomb/v3po/data/VppDataTreeSnapshot.java b/v3po/data-api/src/main/java/io/fd/honeycomb/v3po/data/VppDataTreeSnapshot.java new file mode 100644 index 000000000..665a2e0ae --- /dev/null +++ b/v3po/data-api/src/main/java/io/fd/honeycomb/v3po/data/VppDataTreeSnapshot.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.data; + +import com.google.common.annotations.Beta; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification; + +/** + * Read-only snapshot of a {@link ReadableVppDataTree}. + */ +@Beta +public interface VppDataTreeSnapshot extends ReadableVppDataTree { + + /** + * Creates a new VPP data tree modification. + * + * @return A new data tree modification + */ + DataTreeModification newModification(); +} diff --git a/v3po/data-impl/pom.xml b/v3po/data-impl/pom.xml new file mode 100644 index 000000000..59a5834ac --- /dev/null +++ b/v3po/data-impl/pom.xml @@ -0,0 +1,86 @@ + + + + api-parent + io.fd.honeycomb.common + 1.0.0-SNAPSHOT + ../../common/api-parent + + + 4.0.0 + io.fd.honeycomb.v3po + data-impl + 1.0.0-SNAPSHOT + bundle + + + + io.fd.honeycomb.v3po + data-api + ${project.version} + + + io.fd.honeycomb.v3po + translate-utils + ${project.version} + + + com.google.guava + guava + + + org.opendaylight.mdsal + mdsal-binding-dom-codec + + + org.opendaylight.controller + sal-core-api + 1.3.0-Beryllium + + + + + junit + junit + test + + + + org.mockito + mockito-all + test + + + + + io.fd.honeycomb.v3po + v3po-api + 1.0.0-SNAPSHOT + test + + + + + + + maven-jar-plugin + + + org.apache.felix + maven-bundle-plugin + true + + + ${project.groupId}.${project.artifactId} + + io.fd.honeycomb.v3po.data.impl.* + + + + + + + + \ No newline at end of file diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataTreeUtils.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataTreeUtils.java new file mode 100644 index 000000000..83ed0f263 --- /dev/null +++ b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataTreeUtils.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.data.impl; + +import com.google.common.base.Preconditions; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import javax.annotation.Nonnull; +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.DataContainerChild; +import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Utility class for various operations on DataTree. + */ +final class DataTreeUtils { + private static final Logger LOG = LoggerFactory.getLogger(DataTreeUtils.class); + + private DataTreeUtils() { + throw new UnsupportedOperationException("Can't instantiate util class"); + } + + /** + * Translates children of supplied YANG ContainerNode into Binding data. + * + * @param parent ContainerNode representing data + * @param serializer service for serialization between Java Binding Data representation and NormalizedNode + * representation. + * @return NormalizedNode representation of parent's node children + */ + static Map, DataObject> childrenFromNormalized(@Nonnull final DataContainerNode parent, + @Nonnull final BindingNormalizedNodeSerializer serializer) { + + Preconditions.checkNotNull(parent, "parent node should not be null"); + Preconditions.checkNotNull(serializer, "serializer should not be null"); + + final Map, DataObject> map = new HashMap<>(); + + final Collection> children = + parent.getValue(); + + for (final DataContainerChild child : children) { + final YangInstanceIdentifier.PathArgument pathArgument = child.getIdentifier(); + final YangInstanceIdentifier identifier = YangInstanceIdentifier.create(pathArgument); + LOG.debug("VppConfigDataProxy.extractDataObject() child={}, pathArgument={}, identifier={}", child, + pathArgument, identifier); + + final Map.Entry, DataObject> entry = serializer.fromNormalizedNode(identifier, child); + if (entry != null) { + map.put(entry.getKey(), entry.getValue()); + } + } + + return map; + } +} diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadWriteTransaction.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadWriteTransaction.java new file mode 100644 index 000000000..88b46437e --- /dev/null +++ b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadWriteTransaction.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.data.impl; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.ListenableFuture; +import javax.annotation.Nonnull; +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +/** + * Composite DOM transaction that delegates reads to a {@link DOMDataReadTransaction} delegate and writes to a {@link + * DOMDataWriteTransaction} delegate. + */ +final class ReadWriteTransaction implements DOMDataReadWriteTransaction { + + private final DOMDataReadOnlyTransaction delegateReadTx; + private final DOMDataWriteTransaction delegateWriteTx; + + ReadWriteTransaction(@Nonnull final DOMDataReadOnlyTransaction delegateReadTx, + @Nonnull final DOMDataWriteTransaction delegateWriteTx) { + this.delegateReadTx = Preconditions.checkNotNull(delegateReadTx, "delegateReadTx should not be null"); + this.delegateWriteTx = Preconditions.checkNotNull(delegateWriteTx, "delegateWriteTx should not be null"); + } + + @Override + public boolean cancel() { + delegateReadTx.close(); + return delegateWriteTx.cancel(); + } + + @Override + public void put(final LogicalDatastoreType store, final YangInstanceIdentifier path, + final NormalizedNode data) { + delegateWriteTx.put(store, path, data); + } + + @Override + public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path, + final NormalizedNode data) { + delegateWriteTx.merge(store, path, data); + } + + @Override + public void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) { + delegateWriteTx.delete(store, path); + } + + @Override + public CheckedFuture submit() { + return delegateWriteTx.submit(); + } + + @Override + public ListenableFuture> commit() { + return delegateWriteTx.commit(); + } + + @Override + public CheckedFuture>, ReadFailedException> read(final LogicalDatastoreType store, + final YangInstanceIdentifier path) { + return delegateReadTx.read(store, path); + } + + @Override + public CheckedFuture exists(final LogicalDatastoreType store, + final YangInstanceIdentifier path) { + return delegateReadTx.exists(store, path); + } + + @Override + public Object getIdentifier() { + return this; + } +} + diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppConfigDataTree.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppConfigDataTree.java new file mode 100644 index 000000000..6e01306b0 --- /dev/null +++ b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppConfigDataTree.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.data.impl; + +import static com.google.common.base.Preconditions.checkNotNull; +import static io.fd.honeycomb.v3po.data.impl.DataTreeUtils.childrenFromNormalized; + +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.data.ReadableVppDataTree; +import io.fd.honeycomb.v3po.data.VppDataTree; +import io.fd.honeycomb.v3po.data.VppDataTreeSnapshot; +import io.fd.honeycomb.v3po.translate.TranslationException; +import io.fd.honeycomb.v3po.translate.util.write.TransactionWriteContext; +import io.fd.honeycomb.v3po.translate.write.WriteContext; +import io.fd.honeycomb.v3po.translate.write.WriterRegistry; +import java.util.Collections; +import java.util.Map; +import javax.annotation.Nonnull; +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.DataContainerNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * VppDataTree implementation for configuration data. + */ +public final class VppConfigDataTree implements VppDataTree { + + private static final Logger LOG = LoggerFactory.getLogger(VppConfigDataTree.class); + + private final BindingNormalizedNodeSerializer serializer; + private final DataTree dataTree; + private final WriterRegistry writer; + public static final ReadableVppDataTree EMPTY_OPERATIONAL = new ReadableVppDataTree() { + @Override + public CheckedFuture>, ReadFailedException> read( + @Nonnull final YangInstanceIdentifier path) { + return Futures.immediateCheckedFuture(Optional.>absent()); + } + }; + + /** + * Creates configuration data tree instance. + * + * @param serializer service for serialization between Java Binding Data representation and NormalizedNode + * representation. + * @param dataTree data tree for configuration data representation + * @param vppWriter service for translation between Java Binding Data and Vpp. + */ + public VppConfigDataTree(@Nonnull final BindingNormalizedNodeSerializer serializer, + @Nonnull final DataTree dataTree, @Nonnull final WriterRegistry vppWriter) { + this.serializer = checkNotNull(serializer, "serializer should not be null"); + this.dataTree = checkNotNull(dataTree, "dataTree should not be null"); + this.writer = checkNotNull(vppWriter, "vppWriter should not be null"); + } + + @Override + public VppDataTreeSnapshot takeSnapshot() { + return new ConfigSnapshot(dataTree.takeSnapshot()); + } + + @Override + public void commit(final DataTreeModification modification) + throws DataValidationFailedException, TranslationException { + dataTree.validate(modification); + + final DataTreeCandidate candidate = dataTree.prepare(modification); + + final DataTreeCandidateNode rootNode = candidate.getRootNode(); + final YangInstanceIdentifier rootPath = candidate.getRootPath(); + final Optional> normalizedDataBefore = rootNode.getDataBefore(); + final Optional> normalizedDataAfter = rootNode.getDataAfter(); + LOG.debug("VppConfigDataTree.commit() rootPath={}, rootNode={}, dataBefore={}, dataAfter={}", + rootPath, rootNode, normalizedDataBefore, normalizedDataAfter); + + final Map, DataObject> nodesBefore = extractNetconfData(normalizedDataBefore); + LOG.debug("VppConfigDataTree.commit() extracted nodesBefore={}", nodesBefore.keySet()); + + final Map, DataObject> nodesAfter = extractNetconfData(normalizedDataAfter); + LOG.debug("VppConfigDataTree.commit() extracted nodesAfter={}", nodesAfter.keySet()); + + + final DOMDataReadOnlyTransaction beforeTx = new VppReadOnlyTransaction(EMPTY_OPERATIONAL, takeSnapshot()); + final ConfigSnapshot modificationSnapshot = new ConfigSnapshot(modification); + final DOMDataReadOnlyTransaction afterTx = new VppReadOnlyTransaction(EMPTY_OPERATIONAL, modificationSnapshot); + try(final WriteContext ctx = new TransactionWriteContext(serializer, beforeTx, afterTx)) { + writer.update(nodesBefore, nodesAfter, ctx); + } catch (io.fd.honeycomb.v3po.translate.write.WriterRegistry.BulkUpdateException e) { + LOG.warn("Failed to apply all changes", e); + LOG.info("Trying to revert successful changes for current transaction"); + + try { + e.revertChanges(); + LOG.info("Changes successfully reverted"); + } catch (io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.RevertFailedException revertFailedException) { + // fail with failed revert + LOG.error("Failed to revert successful changes", revertFailedException); + throw revertFailedException; + } + + throw e; // fail with success revert + } catch (TranslationException e) { + LOG.error("Error while processing data change (before={}, after={})", nodesBefore, nodesAfter, e); + throw e; + } + + dataTree.commit(candidate); + } + + private Map, DataObject> extractNetconfData( + final Optional> parentOptional) { + if (parentOptional.isPresent()) { + final DataContainerNode parent = (DataContainerNode) parentOptional.get(); + return childrenFromNormalized(parent, serializer); + } + return Collections.emptyMap(); + } + + private final static class ConfigSnapshot implements VppDataTreeSnapshot { + private final DataTreeSnapshot snapshot; + + ConfigSnapshot(@Nonnull final DataTreeSnapshot snapshot) { + this.snapshot = snapshot; + } + + @Override + public CheckedFuture>, ReadFailedException> read( + @Nonnull final YangInstanceIdentifier path) { + final Optional> node = snapshot.readNode(path); + if (LOG.isTraceEnabled() && node.isPresent()) { + LOG.trace("ConfigSnapshot.read: {}", node.get()); + } + return Futures.immediateCheckedFuture(node); + } + + @Override + public DataTreeModification newModification() { + return snapshot.newModification(); + } + } +} + + + diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppDataBroker.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppDataBroker.java new file mode 100644 index 000000000..5c5248cea --- /dev/null +++ b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppDataBroker.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.data.impl; + +import com.google.common.base.Preconditions; +import io.fd.honeycomb.v3po.data.ReadableVppDataTree; +import io.fd.honeycomb.v3po.data.VppDataTree; +import io.fd.honeycomb.v3po.data.VppDataTreeSnapshot; +import java.util.Collections; +import java.util.Map; +import javax.annotation.Nonnull; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension; +import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +/** + * Data Broker which provides data transaction functionality for VPP using {@link NormalizedNode} data format. + */ +public class VppDataBroker implements DOMDataBroker { + + private final ReadableVppDataTree operationalData; + private final VppDataTree configDataTree; + + /** + * Creates VppDataBroker instance. + * + * @param operationalData VPP operational data + * @param configDataTree VPP configuration data + */ + public VppDataBroker(@Nonnull final ReadableVppDataTree operationalData, + @Nonnull final VppDataTree configDataTree) { + this.operationalData = Preconditions.checkNotNull(operationalData, "operationalData should not be null"); + this.configDataTree = Preconditions.checkNotNull(configDataTree, "configDataProxy should not be null"); + } + + @Override + public DOMDataReadOnlyTransaction newReadOnlyTransaction() { + return new VppReadOnlyTransaction(operationalData, configDataTree.takeSnapshot()); + } + + @Override + public DOMDataReadWriteTransaction newReadWriteTransaction() { + // todo use the same snapshot + final VppDataTreeSnapshot configSnapshot = configDataTree.takeSnapshot(); + final DOMDataReadOnlyTransaction readOnlyTx = new VppReadOnlyTransaction(operationalData, configSnapshot); + final DOMDataWriteTransaction writeOnlyTx = new VppWriteTransaction(configDataTree, configSnapshot); + return new ReadWriteTransaction(readOnlyTx, writeOnlyTx); + } + + @Override + public DOMDataWriteTransaction newWriteOnlyTransaction() { + return new VppWriteTransaction(configDataTree); + } + + @Override + public ListenerRegistration registerDataChangeListener(final LogicalDatastoreType store, + final YangInstanceIdentifier path, + final DOMDataChangeListener listener, + final DataChangeScope triggeringScope) { + throw new UnsupportedOperationException("Not supported"); + } + + @Override + public DOMTransactionChain createTransactionChain(final TransactionChainListener listener) { + throw new UnsupportedOperationException("Not supported"); + } + + @Nonnull + @Override + public Map, DOMDataBrokerExtension> getSupportedExtensions() { + return Collections.emptyMap(); + } +} + + diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppOperationalDataTree.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppOperationalDataTree.java new file mode 100644 index 000000000..fc13606e6 --- /dev/null +++ b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppOperationalDataTree.java @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.data.impl; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.Iterables.getOnlyElement; + +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.collect.Collections2; +import com.google.common.collect.Multimap; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; +import io.fd.honeycomb.v3po.data.ReadableVppDataTree; +import io.fd.honeycomb.v3po.translate.Context; +import io.fd.honeycomb.v3po.translate.read.ReadContext; +import io.fd.honeycomb.v3po.translate.read.ReadFailedException; +import io.fd.honeycomb.v3po.translate.read.ReaderRegistry; +import java.util.Collection; +import java.util.Map; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +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.ContainerNode; +import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; +import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; +import org.opendaylight.yangtools.yang.data.api.schema.MapNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode; +import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode; +import org.opendaylight.yangtools.yang.data.impl.schema.Builders; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * ReadableVppDataTree implementation for operational data. + */ +public final class VppOperationalDataTree implements ReadableVppDataTree { + private static final Logger LOG = LoggerFactory.getLogger(VppOperationalDataTree.class); + + private final BindingNormalizedNodeSerializer serializer; + private final ReaderRegistry readerRegistry; + private final SchemaContext globalContext; + + /** + * Creates operational data tree instance. + * + * @param serializer service for serialization between Java Binding Data representation and NormalizedNode + * representation. + * @param globalContext service for obtaining top level context data from all yang modules. + * @param readerRegistry service responsible for translation between DataObjects and VPP APIs. + */ + public VppOperationalDataTree(@Nonnull BindingNormalizedNodeSerializer serializer, + @Nonnull final SchemaContext globalContext, @Nonnull ReaderRegistry readerRegistry) { + this.globalContext = checkNotNull(globalContext, "serializer should not be null"); + this.serializer = checkNotNull(serializer, "serializer should not be null"); + this.readerRegistry = checkNotNull(readerRegistry, "reader should not be null"); + } + + @Override + public CheckedFuture>, + org.opendaylight.controller.md.sal.common.api.data.ReadFailedException> read( + @Nonnull final YangInstanceIdentifier yangInstanceIdentifier) { + + try(ReadContext ctx = new ReadContextImpl()) { + if (checkNotNull(yangInstanceIdentifier).equals(YangInstanceIdentifier.EMPTY)) { + return Futures.immediateCheckedFuture(readRoot(ctx)); + } else { + return Futures.immediateCheckedFuture(readNode(yangInstanceIdentifier, ctx)); + } + } catch (ReadFailedException e) { + return Futures.immediateFailedCheckedFuture( + new org.opendaylight.controller.md.sal.common.api.data.ReadFailedException( + "Failed to read VPP data", e)); + } + } + + private Optional> readNode(final YangInstanceIdentifier yangInstanceIdentifier, + final ReadContext ctx) + throws ReadFailedException { + LOG.debug("VppOperationalDataTree.readNode(), yangInstanceIdentifier={}", yangInstanceIdentifier); + final InstanceIdentifier path = serializer.fromYangInstanceIdentifier(yangInstanceIdentifier); + checkNotNull(path, "Invalid instance identifier %s. Cannot create BA equivalent.", yangInstanceIdentifier); + LOG.debug("VppOperationalDataTree.readNode(), path={}", path); + + final Optional dataObject; + + dataObject = readerRegistry.read(path, ctx); + if (dataObject.isPresent()) { + final NormalizedNode value = toNormalizedNodeFunction(path).apply(dataObject.get()); + return Optional.>fromNullable(value); + } else { + return Optional.absent(); + } + } + + private Optional> readRoot(final ReadContext ctx) throws ReadFailedException { + LOG.debug("VppOperationalDataTree.readRoot()"); + + final DataContainerNodeAttrBuilder dataNodeBuilder = + Builders.containerBuilder() + .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(SchemaContext.NAME)); + + final Multimap, ? extends DataObject> dataObjects = + readerRegistry.readAll(ctx); + + for (final InstanceIdentifier instanceIdentifier : dataObjects.keySet()) { + final YangInstanceIdentifier rootElementId = serializer.toYangInstanceIdentifier(instanceIdentifier); + final NormalizedNode node = + wrapDataObjects(rootElementId, instanceIdentifier, dataObjects.get(instanceIdentifier)); + dataNodeBuilder.withChild((DataContainerChild) node); + } + + return Optional.>of(dataNodeBuilder.build()); + } + + private NormalizedNode wrapDataObjects(final YangInstanceIdentifier yangInstanceIdentifier, + final InstanceIdentifier instanceIdentifier, + final Collection dataObjects) { + final Collection> normalizedRootElements = Collections2 + .transform(dataObjects, toNormalizedNodeFunction(instanceIdentifier)); + + final DataSchemaNode schemaNode = + globalContext.getDataChildByName(yangInstanceIdentifier.getLastPathArgument().getNodeType()); + if (schemaNode instanceof ListSchemaNode) { + // In case of a list, wrap all the values in a Mixin parent node + final ListSchemaNode listSchema = (ListSchemaNode) schemaNode; + return wrapListIntoMixinNode(normalizedRootElements, listSchema); + } else { + Preconditions.checkState(dataObjects.size() == 1, "Singleton list was expected"); + return getOnlyElement(normalizedRootElements); + } + } + + private static DataContainerChild wrapListIntoMixinNode( + final Collection> normalizedRootElements, final ListSchemaNode listSchema) { + if (listSchema.getKeyDefinition().isEmpty()) { + final CollectionNodeBuilder listBuilder = + Builders.unkeyedListBuilder(); + for (NormalizedNode normalizedRootElement : normalizedRootElements) { + listBuilder.withChild((UnkeyedListEntryNode) normalizedRootElement); + } + return listBuilder.build(); + } else { + final CollectionNodeBuilder listBuilder = + listSchema.isUserOrdered() + ? Builders.orderedMapBuilder() + : Builders.mapBuilder(); + + for (NormalizedNode normalizedRootElement : normalizedRootElements) { + listBuilder.withChild((MapEntryNode) normalizedRootElement); + } + return listBuilder.build(); + } + } + + @SuppressWarnings("unchecked") + private Function> toNormalizedNodeFunction(final InstanceIdentifier path) { + return new Function>() { + @Override + public NormalizedNode apply(@Nullable final DataObject dataObject) { + LOG.trace("VppOperationalDataTree.toNormalizedNode(), path={}, dataObject={}", path, dataObject); + final Map.Entry> entry = + serializer.toNormalizedNode(path, dataObject); + + LOG.trace("VppOperationalDataTree.toNormalizedNode(), normalizedNodeEntry={}", entry); + return entry.getValue(); + } + }; + } + + private static final class ReadContextImpl implements ReadContext { + public final Context ctx = new Context(); + + @Nonnull + @Override + public Context getContext() { + return ctx; + } + + @Override + public void close() { + // Make sure to clear the storage in case some customizer stored it to prevent memory leaks + ctx.close(); + } + } +} diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppReadOnlyTransaction.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppReadOnlyTransaction.java new file mode 100644 index 000000000..db01591b9 --- /dev/null +++ b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppReadOnlyTransaction.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.data.impl; + +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import io.fd.honeycomb.v3po.data.ReadableVppDataTree; +import io.fd.honeycomb.v3po.data.VppDataTreeSnapshot; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +final class VppReadOnlyTransaction implements DOMDataReadOnlyTransaction { + + private static final Logger LOG = LoggerFactory.getLogger(VppReadOnlyTransaction.class); + private volatile ReadableVppDataTree operationalData; + private volatile VppDataTreeSnapshot configSnapshot; + + VppReadOnlyTransaction(@Nonnull final ReadableVppDataTree operationalData, + @Nonnull final VppDataTreeSnapshot configSnapshot) { + this.operationalData = Preconditions.checkNotNull(operationalData, "operationalData should not be null"); + this.configSnapshot = Preconditions.checkNotNull(configSnapshot, "config should not be null"); + } + + @Override + public void close() { + configSnapshot = null; + operationalData = null; + } + + @Override + public CheckedFuture>, ReadFailedException> read( + final LogicalDatastoreType store, + final YangInstanceIdentifier path) { + LOG.debug("VppReadOnlyTransaction.read(), store={}, path={}", store, path); + + Preconditions.checkState(configSnapshot != null, "Transaction was closed"); + + if (store == LogicalDatastoreType.OPERATIONAL) { + return operationalData.read(path); + } else { + return configSnapshot.read(path); + } + } + + @Override + public CheckedFuture exists(final LogicalDatastoreType store, + final YangInstanceIdentifier path) { + LOG.debug("VppReadOnlyTransaction.exists() store={}, path={}", store, path); + + ListenableFuture listenableFuture = Futures.transform(read(store, path), IS_NODE_PRESENT); + + return Futures.makeChecked(listenableFuture, ANY_EX_TO_READ_FAILED_EXCEPTION_MAPPER); + } + + @Nonnull + @Override + public Object getIdentifier() { + return this; + } + + + private static final Function>, ? extends Boolean> IS_NODE_PRESENT = + new Function>, Boolean>() { + @Nullable + @Override + public Boolean apply(@Nullable final Optional> input) { + return input == null + ? Boolean.FALSE + : input.isPresent(); + } + }; + + private static final Function ANY_EX_TO_READ_FAILED_EXCEPTION_MAPPER = + new Function() { + @Override + public ReadFailedException apply(@Nullable final Exception e) { + return new ReadFailedException("Exists failed", e); + } + }; +} \ No newline at end of file diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppWriteTransaction.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppWriteTransaction.java new file mode 100644 index 000000000..c9766eb21 --- /dev/null +++ b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppWriteTransaction.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.data.impl; + +import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.CANCELED; +import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.COMMITED; +import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.FAILED; +import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.NEW; +import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.SUBMITED; + +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import io.fd.honeycomb.v3po.data.VppDataTree; +import io.fd.honeycomb.v3po.data.VppDataTreeSnapshot; +import io.fd.honeycomb.v3po.translate.TranslationException; +import javax.annotation.Nonnull; +import javax.annotation.concurrent.NotThreadSafe; +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@NotThreadSafe +final class VppWriteTransaction implements DOMDataWriteTransaction { + + private static final Logger LOG = LoggerFactory.getLogger(VppWriteTransaction.class); + private final VppDataTree configDataTree; + private DataTreeModification modification; + private TransactionStatus status; + + VppWriteTransaction(@Nonnull final VppDataTree configDataTree, + @Nonnull final VppDataTreeSnapshot configSnapshot) { + this.configDataTree = Preconditions.checkNotNull(configDataTree, "configDataTree should not be null"); + Preconditions.checkNotNull(configSnapshot, "configSnapshot should not be null"); + // initialize transaction state: + modification = configSnapshot.newModification(); + status = NEW; + } + + VppWriteTransaction(@Nonnull final VppDataTree configDataTree) { + this(configDataTree, configDataTree.takeSnapshot()); + } + + private static void checkConfigurationWrite(final LogicalDatastoreType store) { + Preconditions.checkArgument(LogicalDatastoreType.CONFIGURATION == store, "Write is not supported for operational data store"); + } + + private void checkIsNew() { + Preconditions.checkState(status == NEW, "Transaction was submitted or canceled"); + Preconditions.checkState(modification != null, "VPPDataTree modification should not be null"); + } + + @Override + public void put(final LogicalDatastoreType store, final YangInstanceIdentifier path, + final NormalizedNode data) { + LOG.debug("VppWriteTransaction.put() store={}, path={}, data={}", store, path, data); + checkIsNew(); + checkConfigurationWrite(store); + modification.write(path, data); + } + + @Override + public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path, + final NormalizedNode data) { + LOG.debug("VppWriteTransaction.merge() store={}, path={}, data={}", store, path, data); + checkIsNew(); + checkConfigurationWrite(store); + modification.merge(path, data); + } + + @Override + public boolean cancel() { + if (status != NEW) { + // only NEW transactions can be cancelled + return false; + } else { + status = CANCELED; + modification = null; + return true; + } + } + + @Override + public void delete(LogicalDatastoreType store, final YangInstanceIdentifier path) { + LOG.debug("VppWriteTransaction.delete() store={}, path={}", store, path); + checkIsNew(); + checkConfigurationWrite(store); + modification.delete(path); + } + + @Override + public CheckedFuture submit() { + LOG.debug("VppWriteTransaction.submit()"); + checkIsNew(); + + // seal transaction: + modification.ready(); + status = SUBMITED; + + try { + configDataTree.commit(modification); + status = COMMITED; + } catch (DataValidationFailedException | TranslationException e) { + status = FAILED; + LOG.error("Failed to commit VPP state modification", e); + return Futures.immediateFailedCheckedFuture( + new TransactionCommitFailedException("Failed to validate DataTreeModification", e)); + } finally { + modification = null; + } + return Futures.immediateCheckedFuture(null); + } + + @Override + @Deprecated + public ListenableFuture> commit() { + throw new UnsupportedOperationException("deprecated"); + } + + @Override + public Object getIdentifier() { + return this; + } +} diff --git a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/DataTreeUtilsTest.java b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/DataTreeUtilsTest.java new file mode 100644 index 000000000..40792a135 --- /dev/null +++ b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/DataTreeUtilsTest.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.data.impl; + +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Map; +import org.junit.Test; +import org.mockito.Matchers; +import org.mockito.Mockito; +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.ContainerNode; +import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; + +public class DataTreeUtilsTest { + + @Test + public void testChildrenFromNormalized() throws Exception { + final ContainerNode parent = Mockito.mock(ContainerNode.class); + final BindingNormalizedNodeSerializer serializer = Mockito.mock(BindingNormalizedNodeSerializer.class); + + final Collection list = new ArrayList<>(); + Mockito.doReturn(list).when(parent).getValue(); + + // init child1 (will not be serialized) + final DataContainerChild child1 = Mockito.mock(DataContainerChild.class); + Mockito.when(child1.getIdentifier()).thenReturn(Mockito.mock(YangInstanceIdentifier.PathArgument.class)); + Mockito.when(serializer.fromNormalizedNode(Matchers.any(YangInstanceIdentifier.class), Matchers.eq(child1))).thenReturn(null); + list.add(child1); + + // init child 2 (will be serialized) + final DataContainerChild child2 = Mockito.mock(DataContainerChild.class); + Mockito.when(child2.getIdentifier()).thenReturn(Mockito.mock(YangInstanceIdentifier.PathArgument.class)); + + final Map.Entry entry = Mockito.mock(Map.Entry.class); + final InstanceIdentifier id = Mockito.mock(InstanceIdentifier.class); + Mockito.doReturn(id).when(entry).getKey(); + final DataObject data = Mockito.mock(DataObject.class); + Mockito.doReturn(data).when(entry).getValue(); + Mockito.when(serializer.fromNormalizedNode(Matchers.any(YangInstanceIdentifier.class), Matchers.eq(child2))).thenReturn(entry); + + list.add(child2); + + // run tested method + final Map, DataObject> map = DataTreeUtils.childrenFromNormalized(parent, serializer); + assertEquals(1, map.size()); + assertEquals(data, map.get(id)); + } +} \ No newline at end of file diff --git a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadWriteTransactionTest.java b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadWriteTransactionTest.java new file mode 100644 index 000000000..1b67cd967 --- /dev/null +++ b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadWriteTransactionTest.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.data.impl; + +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.verify; +import static org.mockito.MockitoAnnotations.initMocks; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +public class ReadWriteTransactionTest { + + @Mock + private DOMDataReadOnlyTransaction readTx; + + @Mock + private DOMDataWriteTransaction writeTx; + + private LogicalDatastoreType store; + + @Mock + private YangInstanceIdentifier path; + + @Mock + private NormalizedNode data; + + private ReadWriteTransaction readWriteTx; + + @Before + public void setUp() { + initMocks(this); + store = LogicalDatastoreType.CONFIGURATION; + readWriteTx = new ReadWriteTransaction(readTx, writeTx); + } + + @Test + public void testCancel() { + readWriteTx.cancel(); + verify(writeTx).cancel(); + } + + @Test + public void testPut() { + readWriteTx.put(store, path, data); + verify(writeTx).put(store, path, data); + } + + @Test + public void testMerge() { + readWriteTx.merge(store, path, data); + verify(writeTx).merge(store, path, data); + } + + @Test + public void testDelete() { + readWriteTx.delete(store, path); + verify(writeTx).delete(store, path); + } + + @Test + public void testSubmit() throws Exception { + readWriteTx.submit(); + verify(writeTx).submit(); + } + + + @SuppressWarnings("deprecation") + @Test + public void testCommit() throws Exception { + readWriteTx.commit(); + verify(writeTx).commit(); + } + + @Test + public void testRead() { + readWriteTx.read(store, path); + verify(readTx).read(store, path); + } + + @Test + public void testExists() { + readWriteTx.exists(store, path); + verify(readTx).exists(store, path); + } + + @Test + public void testGetIdentifier() throws Exception { + assertNotNull(readWriteTx.getIdentifier()); + } +} \ No newline at end of file diff --git a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VPPConfigDataTreeTest.java b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VPPConfigDataTreeTest.java new file mode 100644 index 000000000..ecb9ac4ab --- /dev/null +++ b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VPPConfigDataTreeTest.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.data.impl; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyMap; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; +import io.fd.honeycomb.v3po.data.VppDataTreeSnapshot; +import io.fd.honeycomb.v3po.translate.TranslationException; +import io.fd.honeycomb.v3po.translate.write.WriteContext; +import io.fd.honeycomb.v3po.translate.write.WriterRegistry; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +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.ReadFailedException; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Ethernet; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot; + +public class VPPConfigDataTreeTest { + + @Mock + private WriterRegistry vppWriter; + @Mock + private BindingNormalizedNodeSerializer serializer; + @Mock + private DataTree dataTree; + @Mock + private DataTreeModification modification; + + private VppConfigDataTree proxy; + + @Before + public void setUp() { + initMocks(this); + proxy = new VppConfigDataTree(serializer, dataTree, vppWriter); + } + + @Test + public void testRead() throws Exception { + final DataTreeSnapshot snapshot = mock(DataTreeSnapshot.class); + when(dataTree.takeSnapshot()).thenReturn(snapshot); + + final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class); + final Optional node = mock(Optional.class); + doReturn(node).when(snapshot).readNode(path); + + final VppDataTreeSnapshot vppDataTreeSnapshot = proxy.takeSnapshot(); + final CheckedFuture>, ReadFailedException> future = + vppDataTreeSnapshot.read(path); + + verify(dataTree).takeSnapshot(); + verify(snapshot).readNode(path); + + assertTrue(future.isDone()); + assertEquals(node, future.get()); + } + + @Test + public void testNewModification() throws Exception { + final DataTreeSnapshot snapshot = mock(DataTreeSnapshot.class); + when(dataTree.takeSnapshot()).thenReturn(snapshot); + + when(snapshot.newModification()).thenReturn(modification); + + final VppDataTreeSnapshot vppDataTreeSnapshot = proxy.takeSnapshot(); + final DataTreeModification newModification = vppDataTreeSnapshot.newModification(); + verify(dataTree).takeSnapshot(); + verify(snapshot).newModification(); + + assertEquals(modification, newModification); + } + + @Test + public void testCommitSuccessful() throws Exception { + final DataObject dataBefore = mockDataObject("before", Ethernet.class); + final DataObject dataAfter = mockDataObject("after", Ethernet.class); + + // Prepare modification: + final DataTreeCandidateNode rootNode = mockRootNode(); + // data before: + final ContainerNode nodeBefore = mockContainerNode(dataBefore); + when(rootNode.getDataBefore()).thenReturn(Optional.>fromNullable(nodeBefore)); + // data after: + final ContainerNode nodeAfter = mockContainerNode(dataAfter); + when(rootNode.getDataAfter()).thenReturn(Optional.>fromNullable(nodeAfter)); + + // Run the test + proxy.commit(modification); + + // Verify all changes were processed: + verify(vppWriter).update( + mapOf(dataBefore, Ethernet.class), + mapOf(dataAfter, Ethernet.class), + any(WriteContext.class)); + + // Verify modification was validated + verify(dataTree).validate(modification); + } + + private Map, DataObject> mapOf(final DataObject dataBefore, final Class type) { + return eq( + Collections., DataObject>singletonMap(InstanceIdentifier.create(type), + dataBefore)); + } + + private DataObject mockDataObject(final String name, final Class classToMock) { + final DataObject dataBefore = mock(classToMock, name); + doReturn(classToMock).when(dataBefore).getImplementedInterface(); + return dataBefore; + } + + @Test + public void testCommitUndoSuccessful() throws Exception { + // Prepare data changes: + final DataObject dataBefore = mockDataObject("before", Ethernet.class); + final DataObject dataAfter = mockDataObject("after", Ethernet.class); + + final io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter reverter = mock( + io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.class); + + // Fail on update: + final TranslationException failedOnUpdateException = new TranslationException("update failed"); + doThrow(new io.fd.honeycomb.v3po.translate.write.WriterRegistry.BulkUpdateException(InstanceIdentifier.create(Ethernet.class), reverter, + failedOnUpdateException)).when(vppWriter).update(anyMap(), anyMap(), any(WriteContext.class)); + + // Prepare modification: + final DataTreeCandidateNode rootNode = mockRootNode(); + // data before: + final ContainerNode nodeBefore = mockContainerNode(dataBefore); + when(rootNode.getDataBefore()).thenReturn(Optional.>fromNullable(nodeBefore)); + // data after: + final ContainerNode nodeAfter = mockContainerNode(dataAfter); + when(rootNode.getDataAfter()).thenReturn(Optional.>fromNullable(nodeAfter)); + + // Run the test + try { + proxy.commit(modification); + } catch (io.fd.honeycomb.v3po.translate.write.WriterRegistry.BulkUpdateException e) { + verify(vppWriter).update(anyMap(), anyMap(), any(WriteContext.class)); + verify(reverter).revert(); + assertEquals(failedOnUpdateException, e.getCause()); + return; + } + + fail("WriterRegistry.BulkUpdateException was expected"); + } + + @Test + public void testCommitUndoFailed() throws Exception { + // Prepare data changes: + final DataObject dataBefore = mockDataObject("before", Ethernet.class); + final DataObject dataAfter = mockDataObject("after", Ethernet.class); + + final io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter reverter = mock( + io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.class); + + // Fail on update: + doThrow(new io.fd.honeycomb.v3po.translate.write.WriterRegistry.BulkUpdateException(InstanceIdentifier.create(Ethernet.class), reverter, + new TranslationException("update failed"))).when(vppWriter).update(anyMap(), anyMap(), any(WriteContext.class)); + + // Fail on revert: + final TranslationException failedOnRevertException = new TranslationException("update failed"); + final io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.RevertFailedException revertFailedException = + new io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.RevertFailedException(Collections.>emptyList(), + failedOnRevertException); + doThrow(revertFailedException).when(reverter).revert(); + + // Prepare modification: + final DataTreeCandidateNode rootNode = mockRootNode(); + // data before: + final ContainerNode nodeBefore = mockContainerNode(dataBefore); + when(rootNode.getDataBefore()).thenReturn(Optional.>fromNullable(nodeBefore)); + // data after: + final ContainerNode nodeAfter = mockContainerNode(dataAfter); + when(rootNode.getDataAfter()).thenReturn(Optional.>fromNullable(nodeAfter)); + + // Run the test + try { + proxy.commit(modification); + } catch (io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.RevertFailedException e) { + verify(vppWriter).update(anyMap(), anyMap(), any(WriteContext.class)); + verify(reverter).revert(); + assertEquals(failedOnRevertException, e.getCause()); + return; + } + + fail("RevertFailedException was expected"); + } + + private DataTreeCandidateNode mockRootNode() { + final DataTreeCandidate candidate = mock(DataTreeCandidate.class); + when(dataTree.prepare(modification)).thenReturn(candidate); + + final DataTreeCandidateNode rootNode = mock(DataTreeCandidateNode.class); + when(candidate.getRootNode()).thenReturn(rootNode); + + return rootNode; + } + + private ContainerNode mockContainerNode(DataObject... modifications) { + final int numberOfChildren = modifications.length; + + final YangInstanceIdentifier.NodeIdentifier identifier = + YangInstanceIdentifier.NodeIdentifier.create(QName.create("/")); + + final ContainerNode node = mock(ContainerNode.class); + when(node.getIdentifier()).thenReturn(identifier); + + final List list = new ArrayList<>(numberOfChildren); + doReturn(list).when(node).getValue(); + + for (DataObject modification : modifications) { + final DataContainerChild child = mock(DataContainerChild.class); + when(child.getIdentifier()).thenReturn(mock(YangInstanceIdentifier.PathArgument.class)); + list.add(child); + + final Map.Entry entry = mock(Map.Entry.class); + final Class implementedInterface = + (Class) modification.getImplementedInterface(); + final InstanceIdentifier id = InstanceIdentifier.create(implementedInterface); + + doReturn(id).when(entry).getKey(); + doReturn(modification).when(entry).getValue(); + doReturn(entry).when(serializer).fromNormalizedNode(any(YangInstanceIdentifier.class), eq(child)); + } + return node; + } +} diff --git a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppDataBrokerTest.java b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppDataBrokerTest.java new file mode 100644 index 000000000..0a7cd80ae --- /dev/null +++ b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppDataBrokerTest.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.data.impl; + +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import io.fd.honeycomb.v3po.data.ReadableVppDataTree; +import io.fd.honeycomb.v3po.data.VppDataTree; +import io.fd.honeycomb.v3po.data.VppDataTreeSnapshot; +import java.util.Map; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension; +import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; + +public class VppDataBrokerTest { + + @Mock + private ReadableVppDataTree operationalData; + @Mock + private VppDataTree confiDataTree; + @Mock + private VppDataTreeSnapshot configSnapshot; + private VppDataBroker broker; + + @Before + public void setUp() { + initMocks(this); + when(confiDataTree.takeSnapshot()).thenReturn(configSnapshot); + broker = new VppDataBroker(operationalData, confiDataTree); + } + + @Test + public void testNewReadWriteTransaction() { + final DOMDataReadWriteTransaction readWriteTx = broker.newReadWriteTransaction(); + final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class); + readWriteTx.read(LogicalDatastoreType.CONFIGURATION, path); + + // verify that read and write transactions use the same config snapshot + verify(configSnapshot).read(path); + verify(configSnapshot).newModification(); + } + + @Test + public void testNewWriteOnlyTransaction() { + final DOMDataWriteTransaction writeTx = broker.newWriteOnlyTransaction(); + + // verify that write transactions use config snapshot + verify(configSnapshot).newModification(); + } + + @Test + public void testNewReadOnlyTransaction() { + final DOMDataReadOnlyTransaction readTx = broker.newReadOnlyTransaction(); + + final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class); + readTx.read(LogicalDatastoreType.CONFIGURATION, path); + + // verify that read transactions use config snapshot + verify(configSnapshot).read(path); + } + + @Test(expected = UnsupportedOperationException.class) + public void testRegisterDataChangeListener() { + final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class); + final DOMDataChangeListener listener = mock(DOMDataChangeListener.class); + broker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, path, listener, + AsyncDataBroker.DataChangeScope.BASE); + } + + @Test(expected = UnsupportedOperationException.class) + public void testCreateTransactionChain() { + final TransactionChainListener listener = mock(TransactionChainListener.class); + broker.createTransactionChain(listener); + } + + @Test + public void testGetSupportedExtensions() { + final Map, DOMDataBrokerExtension> supportedExtensions = + broker.getSupportedExtensions(); + assertTrue(supportedExtensions.isEmpty()); + } + + +} \ No newline at end of file diff --git a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppOperationalDataTreeTest.java b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppOperationalDataTreeTest.java new file mode 100644 index 000000000..d0b45fa65 --- /dev/null +++ b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppOperationalDataTreeTest.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.data.impl; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.same; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import com.google.common.base.Optional; +import com.google.common.collect.Iterables; +import com.google.common.collect.LinkedListMultimap; +import com.google.common.collect.Multimap; +import com.google.common.util.concurrent.CheckedFuture; +import io.fd.honeycomb.v3po.translate.read.ReadContext; +import io.fd.honeycomb.v3po.translate.read.ReaderRegistry; +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.ReadFailedException; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer; +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; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +public class VppOperationalDataTreeTest { + + @Mock + private BindingNormalizedNodeSerializer serializer; + @Mock + private ReaderRegistry reader; + + private VppOperationalDataTree operationalData; + + @Mock + private InstanceIdentifier id; + @Mock + private Map.Entry> entry; + @Mock + private SchemaContext globalContext; + @Mock + private DataSchemaNode schemaNode; + @Mock + private ReadContext readCtx; + + @Before + public void setUp() { + initMocks(this); + operationalData = new VppOperationalDataTree(serializer, globalContext, reader); + doReturn(schemaNode).when(globalContext).getDataChildByName(any(QName.class)); + } + + @Test + public void testReadNode() throws Exception { + final YangInstanceIdentifier yangId = mock(YangInstanceIdentifier.class); + final YangInstanceIdentifier.PathArgument pArg = mock(YangInstanceIdentifier.PathArgument.class); + doReturn(pArg).when(yangId).getLastPathArgument(); + + doReturn(QName.create("namespace", "2012-12-12", "local")).when(pArg).getNodeType(); + doReturn(id).when(serializer).fromYangInstanceIdentifier(yangId); + + final DataObject dataObject = mock(DataObject.class); + doReturn(Optional.of(dataObject)).when(reader).read(same(id), any(ReadContext.class)); + + when(serializer.toNormalizedNode(id, dataObject)).thenReturn(entry); + final DataContainerChild expectedValue = mock(DataContainerChild.class); + doReturn(expectedValue).when(entry).getValue(); + + final CheckedFuture>, ReadFailedException> future = operationalData.read(yangId); + + verify(serializer).fromYangInstanceIdentifier(yangId); + verify(reader).read(same(id), any(ReadContext.class)); + final Optional> result = future.get(); + assertTrue(result.isPresent()); + assertEquals(expectedValue, result.get()); + } + + @Test + public void testReadNonExistingNode() throws Exception { + final YangInstanceIdentifier yangId = mock(YangInstanceIdentifier.class); + doReturn(id).when(serializer).fromYangInstanceIdentifier(yangId); + doReturn(Optional.absent()).when(reader).read(same(id), any(ReadContext.class)); + + final CheckedFuture>, ReadFailedException> future = operationalData.read(yangId); + + verify(serializer).fromYangInstanceIdentifier(yangId); + verify(reader).read(same(id), any(ReadContext.class)); + final Optional> result = future.get(); + assertFalse(result.isPresent()); + } + + @Test + public void testReadFailed() throws Exception{ + doThrow(io.fd.honeycomb.v3po.translate.read.ReadFailedException.class).when(reader).readAll(any(ReadContext.class)); + + final CheckedFuture>, ReadFailedException> future = + operationalData.read( YangInstanceIdentifier.EMPTY); + + try { + future.checkedGet(); + } catch (ReadFailedException e) { + assertTrue(e.getCause() instanceof io.fd.honeycomb.v3po.translate.read.ReadFailedException); + return; + } + fail("ReadFailedException was expected"); + } + + @Test + public void testReadRootWithOneNonListElement() throws Exception { + // Prepare data + final InstanceIdentifier vppStateII = InstanceIdentifier.create(VppState.class); + final VppState vppState = mock(VppState.class); + Multimap, DataObject> dataObjects = LinkedListMultimap.create(); + dataObjects.put(vppStateII, vppState); + doReturn(dataObjects).when(reader).readAll(any(ReadContext.class)); + + // Init serializer + final YangInstanceIdentifier vppYangId = YangInstanceIdentifier.builder().node(VppState.QNAME).build(); + when(serializer.toYangInstanceIdentifier(vppStateII)).thenReturn(vppYangId); + when(serializer.toNormalizedNode(vppStateII, vppState)).thenReturn(entry); + final DataContainerChild vppStateContainer = mock(DataContainerChild.class); + doReturn(vppStateContainer).when(entry).getValue(); + doReturn(vppYangId.getLastPathArgument()).when(vppStateContainer).getIdentifier(); + + // Read root + final CheckedFuture>, ReadFailedException> future = + operationalData.read(YangInstanceIdentifier.EMPTY); + + verify(reader).readAll(any(ReadContext.class)); + verify(serializer).toYangInstanceIdentifier(vppStateII); + verify(serializer).toNormalizedNode(vppStateII, vppState); + + // Check the result is an ContainerNode with only one child + final Optional> result = future.get(); + assertTrue(result.isPresent()); + + final ContainerNode rootNode = (ContainerNode) result.get(); + assertEquals(SchemaContext.NAME, rootNode.getIdentifier().getNodeType()); + assertEquals(vppStateContainer, Iterables.getOnlyElement(rootNode.getValue())); + } +} \ No newline at end of file diff --git a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppReadOnlyTransactionTest.java b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppReadOnlyTransactionTest.java new file mode 100644 index 000000000..b0c64bbdf --- /dev/null +++ b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppReadOnlyTransactionTest.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.data.impl; + +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; +import io.fd.honeycomb.v3po.data.ReadableVppDataTree; +import io.fd.honeycomb.v3po.data.VppDataTreeSnapshot; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +public class VppReadOnlyTransactionTest { + + @Mock + private ReadableVppDataTree operationalData; + @Mock + private VppDataTreeSnapshot configSnapshot; + + private VppReadOnlyTransaction readOnlyTx; + + @Before + public void setUp() { + initMocks(this); + readOnlyTx = new VppReadOnlyTransaction(operationalData, configSnapshot); + } + + @Test + public void testExists() { + final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class); + final CheckedFuture>, ReadFailedException> + future = mock(CheckedFuture.class); + when(operationalData.read(path)).thenReturn(future); + + readOnlyTx.exists(LogicalDatastoreType.OPERATIONAL, path); + + verify(operationalData).read(path); + } + + @Test + public void testGetIdentifier() { + assertNotNull(readOnlyTx.getIdentifier()); + } +} \ No newline at end of file diff --git a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppWriteTransactionTest.java b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppWriteTransactionTest.java new file mode 100644 index 000000000..ad93b148a --- /dev/null +++ b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppWriteTransactionTest.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.data.impl; + +import static junit.framework.TestCase.assertTrue; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import com.google.common.util.concurrent.CheckedFuture; +import io.fd.honeycomb.v3po.data.VppDataTree; +import io.fd.honeycomb.v3po.data.VppDataTreeSnapshot; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException; + +public class VppWriteTransactionTest { + + @Mock + private VppDataTree configDataTree; + @Mock + private VppDataTreeSnapshot configSnapshot; + @Mock + private YangInstanceIdentifier path; + @Mock + private NormalizedNode data; + @Mock + private DataTreeModification dataTreeModification; + + private VppWriteTransaction writeTx; + + @Before + public void setUp() { + initMocks(this); + when(configSnapshot.newModification()).thenReturn(dataTreeModification); + writeTx = new VppWriteTransaction(configDataTree, configSnapshot); + } + + @Test + public void testPut() { + writeTx.put(LogicalDatastoreType.CONFIGURATION, path, data); + verify(dataTreeModification).write(path, data); + } + + @Test(expected = IllegalArgumentException.class) + public void testPutOperational() { + writeTx.put(LogicalDatastoreType.OPERATIONAL, path, data); + verify(dataTreeModification).write(path, data); + } + + @Test(expected = IllegalStateException.class) + public void testOnFinishedTx() { + writeTx.submit(); + writeTx.put(LogicalDatastoreType.CONFIGURATION, path, data); + verify(dataTreeModification).write(path, data); + } + + @Test + public void testMerge() { + writeTx.merge(LogicalDatastoreType.CONFIGURATION, path, data); + verify(dataTreeModification).merge(path, data); + } + + @Test + public void testCancel() { + assertTrue(writeTx.cancel()); + } + + @Test + public void testCancelFinished() { + writeTx.submit(); + assertFalse(writeTx.cancel()); + } + + @Test + public void testDelete() { + writeTx.delete(LogicalDatastoreType.CONFIGURATION, path); + verify(dataTreeModification).delete(path); + } + + @Test + public void testSubmit() throws Exception { + writeTx.submit(); + verify(dataTreeModification).ready(); + verify(configDataTree).commit(dataTreeModification); + } + + @Test + public void testSubmitFailed() throws Exception { + doThrow(mock(DataValidationFailedException.class)).when(configDataTree).commit(dataTreeModification); + final CheckedFuture future = writeTx.submit(); + try { + future.get(); + } catch (Exception e) { + assertTrue(e.getCause() instanceof TransactionCommitFailedException); + return; + } + fail("Expected exception to be thrown"); + + } + + @Test(expected = UnsupportedOperationException.class) + public void testCommit() { + writeTx.commit(); + } + + @Test + public void testGetIdentifier() { + assertNotNull(writeTx.getIdentifier()); + } +} \ No newline at end of file diff --git a/v3po/features/pom.xml b/v3po/features/pom.xml index 810cec5e0..ce4132552 100644 --- a/v3po/features/pom.xml +++ b/v3po/features/pom.xml @@ -133,6 +133,21 @@ v3po-api ${project.version} + + ${project.groupId} + config + ${project.version} + + + ${project.groupId} + data-api + ${project.version} + + + ${project.groupId} + data-impl + ${project.version} + ${project.groupId} translate-api diff --git a/v3po/features/src/main/features/features.xml b/v3po/features/src/main/features/features.xml index 1f5237876..e6a8a64f3 100644 --- a/v3po/features/src/main/features/features.xml +++ b/v3po/features/src/main/features/features.xml @@ -39,6 +39,9 @@ mvn:io.fd.honeycomb.v3po/translate-spi/${project.version} mvn:io.fd.honeycomb.v3po/translate-utils/${project.version} mvn:io.fd.honeycomb.v3po/vpp-translate-utils/${project.version} + mvn:io.fd.honeycomb.v3po/config/${project.version} + mvn:io.fd.honeycomb.v3po/data-api/${project.version} + mvn:io.fd.honeycomb.v3po/data-impl/${project.version} mvn:io.fd.honeycomb.v3po/translate-impl/${project.version} mvn:io.fd.honeycomb.v3po/v3po2vpp/${project.version} wrap:mvn:io.fd.vpp/vppjapi/1.0.0-SNAPSHOT diff --git a/v3po/impl/pom.xml b/v3po/impl/pom.xml index 56dcf8555..be824ca79 100644 --- a/v3po/impl/pom.xml +++ b/v3po/impl/pom.xml @@ -44,6 +44,16 @@ v3po2vpp ${project.version} + + ${project.groupId} + config + ${project.version} + + + ${project.groupId} + data-impl + ${project.version} + io.fd.vpp diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poProvider.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poProvider.java index 0ea4525f0..a97909190 100644 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poProvider.java +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poProvider.java @@ -20,9 +20,8 @@ import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.Futures; -import io.fd.honeycomb.v3po.impl.data.VppDataBrokerInitializationProvider; -import io.fd.honeycomb.v3po.impl.data.ReaderRegistry; -import io.fd.honeycomb.v3po.impl.data.WriterRegistry; +import io.fd.honeycomb.v3po.config.ReaderRegistry; +import io.fd.honeycomb.v3po.config.WriterRegistry; import java.io.IOException; import java.util.Collections; import java.util.HashMap; diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppDataBrokerInitializationProvider.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppDataBrokerInitializationProvider.java new file mode 100644 index 000000000..288463f74 --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppDataBrokerInitializationProvider.java @@ -0,0 +1,282 @@ +/* + * 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; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +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.config.WriterRegistry; +import io.fd.honeycomb.v3po.data.ReadableVppDataTree; +import io.fd.honeycomb.v3po.data.VppDataTree; +import io.fd.honeycomb.v3po.data.impl.VppConfigDataTree; +import io.fd.honeycomb.v3po.data.impl.VppDataBroker; +import io.fd.honeycomb.v3po.data.impl.VppOperationalDataTree; +import io.fd.honeycomb.v3po.translate.read.ReaderRegistry; +import java.util.Collection; +import java.util.Collections; +import javassist.ClassPool; +import javax.annotation.Nonnull; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService; +import org.opendaylight.controller.sal.core.api.Broker; +import org.opendaylight.controller.sal.core.api.Provider; +import org.opendaylight.controller.sal.core.api.model.SchemaService; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer; +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.state.BridgeDomains; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey; +import org.opendaylight.yangtools.binding.data.codec.gen.impl.DataObjectSerializerGenerator; +import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator; +import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry; +import org.opendaylight.yangtools.concepts.ObjectRegistration; +import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy; +import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext; +import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; +import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType; +import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Creates VppDataBroker which uses DataTree instead of DataStore internally in order to obtain better control over the + * data processing in Honeycomb agent + */ +public final class VppDataBrokerInitializationProvider implements Provider, AutoCloseable { + + private static final Logger LOG = LoggerFactory.getLogger(VppDataBrokerInitializationProvider.class); + + private final TopologyId VPP_TOPOLOGY_ID = TopologyId.getDefaultInstance("vpp-topology"); + private final NodeId VPP_TOPOLOGY_NODE_ID = NodeId.getDefaultInstance("vpp"); + private final DataBroker bindingBroker; + private final ReaderRegistry readerRegistry; + private final InstanceIdentifier mountPointPath; + private final WriterRegistry writerRegistry; + private ObjectRegistration mountPointRegistration; + private DOMDataBroker broker; + + public VppDataBrokerInitializationProvider(@Nonnull final DataBroker bindingBroker, + final ReaderRegistry readerRegistry, + final WriterRegistry writerRegistry) { + this.bindingBroker = checkNotNull(bindingBroker, "bindingBroker should not be null"); + this.readerRegistry = checkNotNull(readerRegistry, "readerRegistry should not be null"); + this.writerRegistry = checkNotNull(writerRegistry, "writerRegistry should not be null"); + this.mountPointPath = getMountPointPath(); + } + + // TODO make configurable + private InstanceIdentifier getMountPointPath() { + final InstanceIdentifier networkTopology = + InstanceIdentifier.builder(NetworkTopology.class).build(); + final KeyedInstanceIdentifier topology = + networkTopology.child(Topology.class, new TopologyKey(VPP_TOPOLOGY_ID)); + return topology.child(Node.class, new NodeKey(VPP_TOPOLOGY_NODE_ID)); + } + + @Override + public void onSessionInitiated(final Broker.ProviderSession providerSession) { + LOG.info("Session initialized, providerSession={}", providerSession); + Preconditions.checkState(!isMountPointRegistered(), "Mount point is already registered"); + + final DOMMountPointService mountPointService = providerSession.getService(DOMMountPointService.class); + final SchemaService schemaService = providerSession.getService(SchemaService.class); + + final SchemaContext globalContext = schemaService.getGlobalContext(); + final BindingNormalizedNodeSerializer serializer = initSerializer(globalContext); + final YangInstanceIdentifier path = serializer.toYangInstanceIdentifier(mountPointPath); + + final DOMMountPointService.DOMMountPointBuilder mountPointBuilder = mountPointService.createMountPoint(path); + mountPointBuilder.addInitialSchemaContext(globalContext); + + broker = initVppDataBroker(globalContext, serializer); + mountPointBuilder.addService(DOMDataBroker.class, broker); + + mountPointRegistration = mountPointBuilder.register(); + final DOMMountPoint mountPoint = mountPointRegistration.getInstance(); + LOG.debug("Created mountPoint: identifier={}, schemaContext={}", mountPoint.getIdentifier(), + mountPoint.getSchemaContext()); + + createMountPointPlaceholder(); + + initialVppConfigSynchronization(broker); + } + + @Override + public Collection getProviderFunctionality() { + return Collections.EMPTY_LIST; + } + + private boolean isMountPointRegistered() { + final ReadOnlyTransaction readTx = bindingBroker.newReadOnlyTransaction(); + try { + final Optional cfgPlaceholder = + readTx.read(LogicalDatastoreType.CONFIGURATION, mountPointPath).checkedGet(); + final Optional operPlaceholder = + readTx.read(LogicalDatastoreType.OPERATIONAL, mountPointPath).checkedGet(); + return cfgPlaceholder.isPresent() || operPlaceholder.isPresent(); + } catch (ReadFailedException e) { + throw new IllegalStateException("Failed to read mountpoint placeholder data", e); + } + } + + private BindingNormalizedNodeSerializer initSerializer(final SchemaContext globalContext) { + final JavassistUtils utils = JavassistUtils.forClassPool(ClassPool.getDefault()); + // TODO this produces ClassNotFoundException + //final GeneratedClassLoadingStrategy loading = GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy(); + + // FIXME get global class loader instance + final GeneratedClassLoadingStrategy loadingStrategy = + new GeneratedClassLoadingStrategy() { + @Override + public Class loadClass(final String fullyQualifiedName) + throws ClassNotFoundException { + return Class.forName(fullyQualifiedName); + } + }; + final DataObjectSerializerGenerator generator = StreamWriterGenerator.create(utils); + + // TODO make configurable: + final BindingNormalizedNodeCodecRegistry serializer = new BindingNormalizedNodeCodecRegistry(generator); + final BindingRuntimeContext context = BindingRuntimeContext.create(loadingStrategy, globalContext); + serializer.onBindingRuntimeContextUpdated(context); + return serializer; + } + + private DOMDataBroker initVppDataBroker(final SchemaContext globalContext, + final BindingNormalizedNodeSerializer serializer) { + final ReadableVppDataTree operationalData = + new VppOperationalDataTree(serializer, globalContext, readerRegistry); // TODO make configurable + + final DataTree dataTree = + InMemoryDataTreeFactory.getInstance().create(TreeType.CONFIGURATION); // TODO make configurable + dataTree.setSchemaContext(globalContext); + + final VppDataTree configDataProxy = new VppConfigDataTree(serializer, dataTree, writerRegistry); // TODO make configurable + return new VppDataBroker(operationalData, configDataProxy); + } + + /** + * Writes placeholder data into MD-SAL's global datastore to indicate the presence of VPP mountpoint. + */ + private void createMountPointPlaceholder() { + final NodeBuilder nodeBuilder = new NodeBuilder(); + nodeBuilder.setKey(new NodeKey(VPP_TOPOLOGY_NODE_ID)); + final Node node = nodeBuilder.build(); + + final WriteTransaction writeTx = bindingBroker.newWriteOnlyTransaction(); + writeTx.merge(LogicalDatastoreType.CONFIGURATION, mountPointPath, node, true); + writeTx.merge(LogicalDatastoreType.OPERATIONAL, mountPointPath, node, true); + + try { + writeTx.submit().checkedGet(); + } catch (TransactionCommitFailedException e) { + throw new IllegalStateException("Failed to create mountpoint placeholder", e); + } + } + + // TODO operational and config models are not 1-1 + // decide what part of operational data should be written to config during initialization + private void initialVppConfigSynchronization(final DOMDataBroker broker) { + // read from operational + final DOMDataReadOnlyTransaction readTx = broker.newReadOnlyTransaction(); + + final YangInstanceIdentifier + id = YangInstanceIdentifier.builder().node(VppState.QNAME).node(BridgeDomains.QNAME).build(); + + LOG.trace("initialVppStateSynchronization id: {}", id); + + final ListenableFuture writeFuture = Futures.transform( + readTx.read(LogicalDatastoreType.OPERATIONAL, id), + new AsyncFunction>, Void>() { + @Override + public ListenableFuture apply(final Optional> readResult) + throws Exception { + if (readResult.isPresent()) { + final DOMDataWriteTransaction writeTx = broker.newWriteOnlyTransaction(); + final NormalizedNode node = readResult.get(); + LOG.trace("Read result: {}", node); + + // FIXME + // this will fail because we are reading OPERATIONAL data and writing to CONFIGURATION + // we need to provide extensible way to register initializer that would + // translate between models + + // writeTx.put(LogicalDatastoreType.CONFIGURATION, id, node); + return writeTx.submit(); + } else { + return Futures + .immediateFailedFuture( + new IllegalStateException("Failed to read data from VPP.")); + } + } + }); + + Futures.addCallback(writeFuture, + new LoggingFuturesCallBack("Initializing VPP config DataTree failed", LOG)); + } + + public Optional getBroker() { + return Optional.fromNullable(broker); + } + + @Override + public void close() throws Exception { + if (mountPointRegistration != null) { + mountPointRegistration.close(); + } + + if (broker != null) { + broker = null; + } + + // remove MD-SAL placeholder data for VPP mount point: + final WriteTransaction rwTx = bindingBroker.newWriteOnlyTransaction(); + // does not fail if data is not present: + rwTx.delete(LogicalDatastoreType.CONFIGURATION, mountPointPath); + try { + rwTx.submit().checkedGet(); + } catch (TransactionCommitFailedException e) { + throw new IllegalStateException("Failed to remove mountpoint's placeholder from MD-SAL's global datastore", + e); + } + } +} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/DataTreeUtils.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/DataTreeUtils.java deleted file mode 100644 index bb9da5695..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/DataTreeUtils.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.data; - -import com.google.common.base.Preconditions; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import javax.annotation.Nonnull; -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.DataContainerChild; -import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Utility class for various operations on DataTree. - */ -final class DataTreeUtils { - private static final Logger LOG = LoggerFactory.getLogger(DataTreeUtils.class); - - private DataTreeUtils() { - throw new UnsupportedOperationException("Can't instantiate util class"); - } - - /** - * Translates children of supplied YANG ContainerNode into Binding data. - * - * @param parent ContainerNode representing data - * @param serializer service for serialization between Java Binding Data representation and NormalizedNode - * representation. - * @return NormalizedNode representation of parent's node children - */ - static Map, DataObject> childrenFromNormalized(@Nonnull final DataContainerNode parent, - @Nonnull final BindingNormalizedNodeSerializer serializer) { - - Preconditions.checkNotNull(parent, "parent node should not be null"); - Preconditions.checkNotNull(serializer, "serializer should not be null"); - - final Map, DataObject> map = new HashMap<>(); - - final Collection> children = - parent.getValue(); - - for (final DataContainerChild child : children) { - final YangInstanceIdentifier.PathArgument pathArgument = child.getIdentifier(); - final YangInstanceIdentifier identifier = YangInstanceIdentifier.create(pathArgument); - LOG.debug("VppConfigDataProxy.extractDataObject() child={}, pathArgument={}, identifier={}", child, - pathArgument, identifier); - - final Map.Entry, DataObject> entry = serializer.fromNormalizedNode(identifier, child); - if (entry != null) { - map.put(entry.getKey(), entry.getValue()); - } - } - - return map; - } -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/ReadWriteTransaction.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/ReadWriteTransaction.java deleted file mode 100644 index 7faeba54a..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/ReadWriteTransaction.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.data; - -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -import com.google.common.util.concurrent.CheckedFuture; -import com.google.common.util.concurrent.ListenableFuture; -import javax.annotation.Nonnull; -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; -import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; -import org.opendaylight.yangtools.yang.common.RpcResult; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; - -/** - * Composite DOM transaction that delegates reads to a {@link DOMDataReadTransaction} delegate and writes to a {@link - * DOMDataWriteTransaction} delegate. - */ -final class ReadWriteTransaction implements DOMDataReadWriteTransaction { - - private final DOMDataReadOnlyTransaction delegateReadTx; - private final DOMDataWriteTransaction delegateWriteTx; - - ReadWriteTransaction(@Nonnull final DOMDataReadOnlyTransaction delegateReadTx, - @Nonnull final DOMDataWriteTransaction delegateWriteTx) { - this.delegateReadTx = Preconditions.checkNotNull(delegateReadTx, "delegateReadTx should not be null"); - this.delegateWriteTx = Preconditions.checkNotNull(delegateWriteTx, "delegateWriteTx should not be null"); - } - - @Override - public boolean cancel() { - delegateReadTx.close(); - return delegateWriteTx.cancel(); - } - - @Override - public void put(final LogicalDatastoreType store, final YangInstanceIdentifier path, - final NormalizedNode data) { - delegateWriteTx.put(store, path, data); - } - - @Override - public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path, - final NormalizedNode data) { - delegateWriteTx.merge(store, path, data); - } - - @Override - public void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) { - delegateWriteTx.delete(store, path); - } - - @Override - public CheckedFuture submit() { - return delegateWriteTx.submit(); - } - - @Override - public ListenableFuture> commit() { - return delegateWriteTx.commit(); - } - - @Override - public CheckedFuture>, ReadFailedException> read(final LogicalDatastoreType store, - final YangInstanceIdentifier path) { - return delegateReadTx.read(store, path); - } - - @Override - public CheckedFuture exists(final LogicalDatastoreType store, - final YangInstanceIdentifier path) { - return delegateReadTx.exists(store, path); - } - - @Override - public Object getIdentifier() { - return this; - } -} - diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/ReadableVppDataTree.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/ReadableVppDataTree.java deleted file mode 100644 index 19248ddf0..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/ReadableVppDataTree.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.data; - -import com.google.common.annotations.Beta; -import com.google.common.base.Optional; -import com.google.common.util.concurrent.CheckedFuture; -import javax.annotation.Nonnull; -import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; - -/** - * Facade over VPP data tree that allows reading tree nodes. - */ -@Beta -public interface ReadableVppDataTree { - /** - * Reads a particular node from the VPP data tree. - * - * @param path Path of the node - * @return a CheckFuture containing the result of the read. - */ - CheckedFuture>, ReadFailedException> read(@Nonnull final YangInstanceIdentifier path); -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/ReaderRegistry.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/ReaderRegistry.java deleted file mode 100644 index 5e547094f..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/ReaderRegistry.java +++ /dev/null @@ -1,116 +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.data; - -import com.google.common.base.Optional; -import com.google.common.collect.Multimap; -import io.fd.honeycomb.v3po.translate.impl.read.CompositeChildReader; -import io.fd.honeycomb.v3po.translate.impl.read.CompositeListReader; -import io.fd.honeycomb.v3po.translate.impl.read.CompositeRootReader; -import io.fd.honeycomb.v3po.translate.util.read.DelegatingReaderRegistry; -import io.fd.honeycomb.v3po.translate.util.read.ReflexiveChildReaderCustomizer; -import io.fd.honeycomb.v3po.translate.util.read.ReflexiveRootReaderCustomizer; -import io.fd.honeycomb.v3po.translate.util.RWUtils; -import io.fd.honeycomb.v3po.translate.read.ChildReader; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.read.Reader; -import io.fd.honeycomb.v3po.translate.v3po.vppstate.BridgeDomainCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.vppstate.VersionCustomizer; -import java.util.ArrayList; -import java.util.Collections; -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.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.vppjapi.vppApi; - -// TODO use some DI framework instead of singleton -public class ReaderRegistry implements io.fd.honeycomb.v3po.translate.read.ReaderRegistry { - - private static ReaderRegistry instance; - - private final DelegatingReaderRegistry reader; - - private ReaderRegistry(@Nonnull final vppApi vppApi) { - final CompositeRootReader vppStateReader = initVppStateReader(vppApi); - // TODO add more root readers - reader = new DelegatingReaderRegistry(Collections.>singletonList(vppStateReader)); - } - - private static CompositeRootReader initVppStateReader(@Nonnull final vppApi vppApi) { - - final ChildReader versionReader = new CompositeChildReader<>( - Version.class, new VersionCustomizer(vppApi)); - - final CompositeListReader - bridgeDomainReader = new CompositeListReader<>( - BridgeDomain.class, - new BridgeDomainCustomizer(vppApi)); - - final ChildReader bridgeDomainsReader = new CompositeChildReader<>( - BridgeDomains.class, - RWUtils.singletonChildReaderList(bridgeDomainReader), - new ReflexiveChildReaderCustomizer<>(BridgeDomainsBuilder.class)); - - final List>> childVppReaders = new ArrayList<>(); - childVppReaders.add(versionReader); - childVppReaders.add(bridgeDomainsReader); - - return new CompositeRootReader<>( - VppState.class, - childVppReaders, - RWUtils.emptyAugReaderList(), - new ReflexiveRootReaderCustomizer<>(VppStateBuilder.class)); - } - - public static synchronized ReaderRegistry getInstance(@Nonnull final vppApi vppApi) { - if (instance == null) { - instance = new ReaderRegistry(vppApi); - } - return instance; - } - - @Nonnull - @Override - public Multimap, ? extends DataObject> readAll( - @Nonnull final ReadContext ctx) throws ReadFailedException { - return reader.readAll(ctx); - } - - @Nonnull - @Override - public Optional read(@Nonnull final InstanceIdentifier id, - @Nonnull final ReadContext ctx) throws ReadFailedException { - return reader.read(id, ctx); - } - - @Nonnull - @Override - public InstanceIdentifier getManagedDataObjectType() { - return reader.getManagedDataObjectType(); - } -} 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 deleted file mode 100644 index 1a631fc2e..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppConfigDataTree.java +++ /dev/null @@ -1,167 +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.data; - -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.translate.TranslationException; -import io.fd.honeycomb.v3po.translate.util.write.TransactionWriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import java.util.Collections; -import java.util.Map; -import javax.annotation.Nonnull; -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.DataContainerNode; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * VppDataTree implementation for configuration data. - */ -public final class VppConfigDataTree implements VppDataTree { - - private static final Logger LOG = LoggerFactory.getLogger(VppConfigDataTree.class); - - private final BindingNormalizedNodeSerializer serializer; - private final DataTree dataTree; - private final WriterRegistry writer; - public static final ReadableVppDataTree EMPTY_OPERATIONAL = new ReadableVppDataTree() { - @Override - public CheckedFuture>, ReadFailedException> read( - @Nonnull final YangInstanceIdentifier path) { - return Futures.immediateCheckedFuture(Optional.>absent()); - } - }; - - /** - * Creates configuration data tree instance. - * - * @param serializer service for serialization between Java Binding Data representation and NormalizedNode - * representation. - * @param dataTree data tree for configuration data representation - * @param vppWriter service for translation between Java Binding Data and Vpp. - */ - public VppConfigDataTree(@Nonnull final BindingNormalizedNodeSerializer serializer, - @Nonnull final DataTree dataTree, @Nonnull final WriterRegistry vppWriter) { - this.serializer = checkNotNull(serializer, "serializer should not be null"); - this.dataTree = checkNotNull(dataTree, "dataTree should not be null"); - this.writer = checkNotNull(vppWriter, "vppWriter should not be null"); - } - - @Override - public VppDataTreeSnapshot takeSnapshot() { - return new ConfigSnapshot(dataTree.takeSnapshot()); - } - - @Override - public void commit(final DataTreeModification modification) - throws DataValidationFailedException, TranslationException { - dataTree.validate(modification); - - final DataTreeCandidate candidate = dataTree.prepare(modification); - - final DataTreeCandidateNode rootNode = candidate.getRootNode(); - final YangInstanceIdentifier rootPath = candidate.getRootPath(); - final Optional> normalizedDataBefore = rootNode.getDataBefore(); - final Optional> normalizedDataAfter = rootNode.getDataAfter(); - LOG.debug("VppConfigDataTree.commit() rootPath={}, rootNode={}, dataBefore={}, dataAfter={}", - rootPath, rootNode, normalizedDataBefore, normalizedDataAfter); - - final Map, DataObject> nodesBefore = extractNetconfData(normalizedDataBefore); - LOG.debug("VppConfigDataTree.commit() extracted nodesBefore={}", nodesBefore.keySet()); - - final Map, DataObject> nodesAfter = extractNetconfData(normalizedDataAfter); - LOG.debug("VppConfigDataTree.commit() extracted nodesAfter={}", nodesAfter.keySet()); - - - final DOMDataReadOnlyTransaction beforeTx = new VppReadOnlyTransaction(EMPTY_OPERATIONAL, takeSnapshot()); - final ConfigSnapshot modificationSnapshot = new ConfigSnapshot(modification); - final DOMDataReadOnlyTransaction afterTx = new VppReadOnlyTransaction(EMPTY_OPERATIONAL, modificationSnapshot); - try(final WriteContext ctx = new TransactionWriteContext(serializer, beforeTx, afterTx)) { - writer.update(nodesBefore, nodesAfter, ctx); - } catch (io.fd.honeycomb.v3po.translate.write.WriterRegistry.BulkUpdateException e) { - LOG.warn("Failed to apply all changes", e); - LOG.info("Trying to revert successful changes for current transaction"); - - try { - e.revertChanges(); - LOG.info("Changes successfully reverted"); - } catch (io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.RevertFailedException revertFailedException) { - // fail with failed revert - LOG.error("Failed to revert successful changes", revertFailedException); - throw revertFailedException; - } - - throw e; // fail with success revert - } catch (TranslationException e) { - LOG.error("Error while processing data change (before={}, after={})", nodesBefore, nodesAfter, e); - throw e; - } - - dataTree.commit(candidate); - } - - private Map, DataObject> extractNetconfData( - final Optional> parentOptional) { - if (parentOptional.isPresent()) { - final DataContainerNode parent = (DataContainerNode) parentOptional.get(); - return DataTreeUtils.childrenFromNormalized(parent, serializer); - } - return Collections.emptyMap(); - } - - private final static class ConfigSnapshot implements VppDataTreeSnapshot { - private final DataTreeSnapshot snapshot; - - ConfigSnapshot(@Nonnull final DataTreeSnapshot snapshot) { - this.snapshot = snapshot; - } - - @Override - public CheckedFuture>, ReadFailedException> read( - @Nonnull final YangInstanceIdentifier path) { - final Optional> node = snapshot.readNode(path); - if (LOG.isTraceEnabled() && node.isPresent()) { - LOG.trace("ConfigSnapshot.read: {}", node.get()); - } - return Futures.immediateCheckedFuture(node); - } - - @Override - public DataTreeModification newModification() { - return snapshot.newModification(); - } - } -} - - - diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataBroker.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataBroker.java deleted file mode 100644 index 97697da65..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataBroker.java +++ /dev/null @@ -1,95 +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.data; - -import com.google.common.base.Preconditions; -import java.util.Collections; -import java.util.Map; -import javax.annotation.Nonnull; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener; -import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; -import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension; -import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain; -import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; - -/** - * Data Broker which provides data transaction functionality for VPP using {@link NormalizedNode} data format. - */ -public class VppDataBroker implements DOMDataBroker { - - private final ReadableVppDataTree operationalData; - private final VppDataTree configDataTree; - - /** - * Creates VppDataBroker instance. - * - * @param operationalData VPP operational data - * @param configDataTree VPP configuration data - */ - public VppDataBroker(@Nonnull final ReadableVppDataTree operationalData, - @Nonnull final VppDataTree configDataTree) { - this.operationalData = Preconditions.checkNotNull(operationalData, "operationalData should not be null"); - this.configDataTree = Preconditions.checkNotNull(configDataTree, "configDataProxy should not be null"); - } - - @Override - public DOMDataReadOnlyTransaction newReadOnlyTransaction() { - return new VppReadOnlyTransaction(operationalData, configDataTree.takeSnapshot()); - } - - @Override - public DOMDataReadWriteTransaction newReadWriteTransaction() { - // todo use the same snapshot - final VppDataTreeSnapshot configSnapshot = configDataTree.takeSnapshot(); - final DOMDataReadOnlyTransaction readOnlyTx = new VppReadOnlyTransaction(operationalData, configSnapshot); - final DOMDataWriteTransaction writeOnlyTx = new VppWriteTransaction(configDataTree, configSnapshot); - return new ReadWriteTransaction(readOnlyTx, writeOnlyTx); - } - - @Override - public DOMDataWriteTransaction newWriteOnlyTransaction() { - return new VppWriteTransaction(configDataTree); - } - - @Override - public ListenerRegistration registerDataChangeListener(final LogicalDatastoreType store, - final YangInstanceIdentifier path, - final DOMDataChangeListener listener, - final DataChangeScope triggeringScope) { - throw new UnsupportedOperationException("Not supported"); - } - - @Override - public DOMTransactionChain createTransactionChain(final TransactionChainListener listener) { - throw new UnsupportedOperationException("Not supported"); - } - - @Nonnull - @Override - public Map, DOMDataBrokerExtension> getSupportedExtensions() { - return Collections.emptyMap(); - } -} - - 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 deleted file mode 100644 index bdfc89079..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerInitializationProvider.java +++ /dev/null @@ -1,277 +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.data; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -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.translate.read.ReaderRegistry; -import java.util.Collection; -import java.util.Collections; -import javassist.ClassPool; -import javax.annotation.Nonnull; -import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; -import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; -import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; -import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; -import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService; -import org.opendaylight.controller.sal.core.api.Broker; -import org.opendaylight.controller.sal.core.api.Provider; -import org.opendaylight.controller.sal.core.api.model.SchemaService; -import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer; -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.state.BridgeDomains; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey; -import org.opendaylight.yangtools.binding.data.codec.gen.impl.DataObjectSerializerGenerator; -import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator; -import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry; -import org.opendaylight.yangtools.concepts.ObjectRegistration; -import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy; -import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext; -import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; -import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType; -import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Creates VppDataBroker which uses DataTree instead of DataStore internally in order to obtain better control over the - * data processing in Honeycomb agent - */ -public final class VppDataBrokerInitializationProvider implements Provider, AutoCloseable { - - private static final Logger LOG = LoggerFactory.getLogger(VppDataBrokerInitializationProvider.class); - - private final TopologyId VPP_TOPOLOGY_ID = TopologyId.getDefaultInstance("vpp-topology"); - private final NodeId VPP_TOPOLOGY_NODE_ID = NodeId.getDefaultInstance("vpp"); - private final DataBroker bindingBroker; - private final ReaderRegistry readerRegistry; - private final InstanceIdentifier mountPointPath; - private final WriterRegistry writerRegistry; - private ObjectRegistration mountPointRegistration; - private DOMDataBroker broker; - - public VppDataBrokerInitializationProvider(@Nonnull final DataBroker bindingBroker, - final ReaderRegistry readerRegistry, - final WriterRegistry writerRegistry) { - this.bindingBroker = checkNotNull(bindingBroker, "bindingBroker should not be null"); - this.readerRegistry = checkNotNull(readerRegistry, "readerRegistry should not be null"); - this.writerRegistry = checkNotNull(writerRegistry, "writerRegistry should not be null"); - this.mountPointPath = getMountPointPath(); - } - - // TODO make configurable - private InstanceIdentifier getMountPointPath() { - final InstanceIdentifier networkTopology = - InstanceIdentifier.builder(NetworkTopology.class).build(); - final KeyedInstanceIdentifier topology = - networkTopology.child(Topology.class, new TopologyKey(VPP_TOPOLOGY_ID)); - return topology.child(Node.class, new NodeKey(VPP_TOPOLOGY_NODE_ID)); - } - - @Override - public void onSessionInitiated(final Broker.ProviderSession providerSession) { - LOG.info("Session initialized, providerSession={}", providerSession); - Preconditions.checkState(!isMountPointRegistered(), "Mount point is already registered"); - - final DOMMountPointService mountPointService = providerSession.getService(DOMMountPointService.class); - final SchemaService schemaService = providerSession.getService(SchemaService.class); - - final SchemaContext globalContext = schemaService.getGlobalContext(); - final BindingNormalizedNodeSerializer serializer = initSerializer(globalContext); - final YangInstanceIdentifier path = serializer.toYangInstanceIdentifier(mountPointPath); - - final DOMMountPointService.DOMMountPointBuilder mountPointBuilder = mountPointService.createMountPoint(path); - mountPointBuilder.addInitialSchemaContext(globalContext); - - broker = initVppDataBroker(globalContext, serializer); - mountPointBuilder.addService(DOMDataBroker.class, broker); - - mountPointRegistration = mountPointBuilder.register(); - final DOMMountPoint mountPoint = mountPointRegistration.getInstance(); - LOG.debug("Created mountPoint: identifier={}, schemaContext={}", mountPoint.getIdentifier(), - mountPoint.getSchemaContext()); - - createMountPointPlaceholder(); - - initialVppConfigSynchronization(broker); - } - - @Override - public Collection getProviderFunctionality() { - return Collections.EMPTY_LIST; - } - - private boolean isMountPointRegistered() { - final ReadOnlyTransaction readTx = bindingBroker.newReadOnlyTransaction(); - try { - final Optional cfgPlaceholder = - readTx.read(LogicalDatastoreType.CONFIGURATION, mountPointPath).checkedGet(); - final Optional operPlaceholder = - readTx.read(LogicalDatastoreType.OPERATIONAL, mountPointPath).checkedGet(); - return cfgPlaceholder.isPresent() || operPlaceholder.isPresent(); - } catch (ReadFailedException e) { - throw new IllegalStateException("Failed to read mountpoint placeholder data", e); - } - } - - private BindingNormalizedNodeSerializer initSerializer(final SchemaContext globalContext) { - final JavassistUtils utils = JavassistUtils.forClassPool(ClassPool.getDefault()); - // TODO this produces ClassNotFoundException - //final GeneratedClassLoadingStrategy loading = GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy(); - - // FIXME get global class loader instance - final GeneratedClassLoadingStrategy loadingStrategy = - new GeneratedClassLoadingStrategy() { - @Override - public Class loadClass(final String fullyQualifiedName) - throws ClassNotFoundException { - return Class.forName(fullyQualifiedName); - } - }; - final DataObjectSerializerGenerator generator = StreamWriterGenerator.create(utils); - - // TODO make configurable: - final BindingNormalizedNodeCodecRegistry serializer = new BindingNormalizedNodeCodecRegistry(generator); - final BindingRuntimeContext context = BindingRuntimeContext.create(loadingStrategy, globalContext); - serializer.onBindingRuntimeContextUpdated(context); - return serializer; - } - - private DOMDataBroker initVppDataBroker(final SchemaContext globalContext, - final BindingNormalizedNodeSerializer serializer) { - final ReadableVppDataTree operationalData = - new VppOperationalDataTree(serializer, globalContext, readerRegistry); // TODO make configurable - - final DataTree dataTree = - InMemoryDataTreeFactory.getInstance().create(TreeType.CONFIGURATION); // TODO make configurable - dataTree.setSchemaContext(globalContext); - - final VppDataTree configDataProxy = new VppConfigDataTree(serializer, dataTree, writerRegistry); // TODO make configurable - return new VppDataBroker(operationalData, configDataProxy); - } - - /** - * Writes placeholder data into MD-SAL's global datastore to indicate the presence of VPP mountpoint. - */ - private void createMountPointPlaceholder() { - final NodeBuilder nodeBuilder = new NodeBuilder(); - nodeBuilder.setKey(new NodeKey(VPP_TOPOLOGY_NODE_ID)); - final Node node = nodeBuilder.build(); - - final WriteTransaction writeTx = bindingBroker.newWriteOnlyTransaction(); - writeTx.merge(LogicalDatastoreType.CONFIGURATION, mountPointPath, node, true); - writeTx.merge(LogicalDatastoreType.OPERATIONAL, mountPointPath, node, true); - - try { - writeTx.submit().checkedGet(); - } catch (TransactionCommitFailedException e) { - throw new IllegalStateException("Failed to create mountpoint placeholder", e); - } - } - - // TODO operational and config models are not 1-1 - // decide what part of operational data should be written to config during initialization - private void initialVppConfigSynchronization(final DOMDataBroker broker) { - // read from operational - final DOMDataReadOnlyTransaction readTx = broker.newReadOnlyTransaction(); - - final YangInstanceIdentifier - id = YangInstanceIdentifier.builder().node(VppState.QNAME).node(BridgeDomains.QNAME).build(); - - LOG.trace("initialVppStateSynchronization id: {}", id); - - final ListenableFuture writeFuture = Futures.transform( - readTx.read(LogicalDatastoreType.OPERATIONAL, id), - new AsyncFunction>, Void>() { - @Override - public ListenableFuture apply(final Optional> readResult) - throws Exception { - if (readResult.isPresent()) { - final DOMDataWriteTransaction writeTx = broker.newWriteOnlyTransaction(); - final NormalizedNode node = readResult.get(); - LOG.trace("Read result: {}", node); - - // FIXME - // this will fail because we are reading OPERATIONAL data and writing to CONFIGURATION - // we need to provide extensible way to register initializer that would - // translate between models - - // writeTx.put(LogicalDatastoreType.CONFIGURATION, id, node); - return writeTx.submit(); - } else { - return Futures - .immediateFailedFuture( - new IllegalStateException("Failed to read data from VPP.")); - } - } - }); - - Futures.addCallback(writeFuture, - new LoggingFuturesCallBack("Initializing VPP config DataTree failed", LOG)); - } - - public Optional getBroker() { - return Optional.fromNullable(broker); - } - - @Override - public void close() throws Exception { - if (mountPointRegistration != null) { - mountPointRegistration.close(); - } - - if (broker != null) { - broker = null; - } - - // remove MD-SAL placeholder data for VPP mount point: - final WriteTransaction rwTx = bindingBroker.newWriteOnlyTransaction(); - // does not fail if data is not present: - rwTx.delete(LogicalDatastoreType.CONFIGURATION, mountPointPath); - try { - rwTx.submit().checkedGet(); - } catch (TransactionCommitFailedException e) { - throw new IllegalStateException("Failed to remove mountpoint's placeholder from MD-SAL's global datastore", - e); - } - } -} 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 deleted file mode 100644 index aba8ab133..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataTree.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.data; - -import com.google.common.annotations.Beta; -import io.fd.honeycomb.v3po.translate.TranslationException; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException; - -/** - * Facade over VPP data tree that allows tree modification. - */ -@Beta -public interface VppDataTree { - /** - * Commits modification to VPP data tree. - * - * @param modification VPP data tree modification - * @throws DataValidationFailedException if modification data is not valid - * @throws TranslationException if commit failed while updating VPP state - */ - void commit(final DataTreeModification modification) throws DataValidationFailedException, TranslationException; - - /** - * Creates read-only snapshot of a VppDataTree. - * - * @return Data tree snapshot. - */ - VppDataTreeSnapshot takeSnapshot(); -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataTreeSnapshot.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataTreeSnapshot.java deleted file mode 100644 index f4d68306f..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataTreeSnapshot.java +++ /dev/null @@ -1,34 +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.data; - -import com.google.common.annotations.Beta; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification; - -/** - * Read-only snapshot of a {@link ReadableVppDataTree}. - */ -@Beta -public interface VppDataTreeSnapshot extends ReadableVppDataTree { - - /** - * Creates a new VPP data tree modification. - * - * @return A new data tree modification - */ - DataTreeModification newModification(); -} 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 deleted file mode 100644 index 8f606fdbf..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppOperationalDataTree.java +++ /dev/null @@ -1,209 +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.data; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.collect.Iterables.getOnlyElement; - -import com.google.common.base.Function; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -import com.google.common.collect.Collections2; -import com.google.common.collect.Multimap; -import com.google.common.util.concurrent.CheckedFuture; -import com.google.common.util.concurrent.Futures; -import io.fd.honeycomb.v3po.translate.Context; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.read.ReaderRegistry; -import java.util.Collection; -import java.util.Map; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -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.ContainerNode; -import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; -import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; -import org.opendaylight.yangtools.yang.data.api.schema.MapNode; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode; -import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode; -import org.opendaylight.yangtools.yang.data.impl.schema.Builders; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder; -import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; -import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * ReadableVppDataTree implementation for operational data. - */ -public final class VppOperationalDataTree implements ReadableVppDataTree { - private static final Logger LOG = LoggerFactory.getLogger(VppOperationalDataTree.class); - - private final BindingNormalizedNodeSerializer serializer; - private final ReaderRegistry readerRegistry; - private final SchemaContext globalContext; - - /** - * Creates operational data tree instance. - * - * @param serializer service for serialization between Java Binding Data representation and NormalizedNode - * representation. - * @param globalContext service for obtaining top level context data from all yang modules. - * @param readerRegistry service responsible for translation between DataObjects and VPP APIs. - */ - public VppOperationalDataTree(@Nonnull BindingNormalizedNodeSerializer serializer, - @Nonnull final SchemaContext globalContext, @Nonnull ReaderRegistry readerRegistry) { - this.globalContext = checkNotNull(globalContext, "serializer should not be null"); - this.serializer = checkNotNull(serializer, "serializer should not be null"); - this.readerRegistry = checkNotNull(readerRegistry, "reader should not be null"); - } - - @Override - public CheckedFuture>, - org.opendaylight.controller.md.sal.common.api.data.ReadFailedException> read( - @Nonnull final YangInstanceIdentifier yangInstanceIdentifier) { - - try(ReadContext ctx = new ReadContextImpl()) { - if (checkNotNull(yangInstanceIdentifier).equals(YangInstanceIdentifier.EMPTY)) { - return Futures.immediateCheckedFuture(readRoot(ctx)); - } else { - return Futures.immediateCheckedFuture(readNode(yangInstanceIdentifier, ctx)); - } - } catch (ReadFailedException e) { - return Futures.immediateFailedCheckedFuture( - new org.opendaylight.controller.md.sal.common.api.data.ReadFailedException( - "Failed to read VPP data", e)); - } - } - - private Optional> readNode(final YangInstanceIdentifier yangInstanceIdentifier, - final ReadContext ctx) - throws ReadFailedException { - LOG.debug("VppOperationalDataTree.readNode(), yangInstanceIdentifier={}", yangInstanceIdentifier); - final InstanceIdentifier path = serializer.fromYangInstanceIdentifier(yangInstanceIdentifier); - checkNotNull(path, "Invalid instance identifier %s. Cannot create BA equivalent.", yangInstanceIdentifier); - LOG.debug("VppOperationalDataTree.readNode(), path={}", path); - - final Optional dataObject; - - dataObject = readerRegistry.read(path, ctx); - if (dataObject.isPresent()) { - final NormalizedNode value = toNormalizedNodeFunction(path).apply(dataObject.get()); - return Optional.>fromNullable(value); - } else { - return Optional.absent(); - } - } - - private Optional> readRoot(final ReadContext ctx) throws ReadFailedException { - LOG.debug("VppOperationalDataTree.readRoot()"); - - final DataContainerNodeAttrBuilder dataNodeBuilder = - Builders.containerBuilder() - .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(SchemaContext.NAME)); - - final Multimap, ? extends DataObject> dataObjects = - readerRegistry.readAll(ctx); - - for (final InstanceIdentifier instanceIdentifier : dataObjects.keySet()) { - final YangInstanceIdentifier rootElementId = serializer.toYangInstanceIdentifier(instanceIdentifier); - final NormalizedNode node = - wrapDataObjects(rootElementId, instanceIdentifier, dataObjects.get(instanceIdentifier)); - dataNodeBuilder.withChild((DataContainerChild) node); - } - - return Optional.>of(dataNodeBuilder.build()); - } - - private NormalizedNode wrapDataObjects(final YangInstanceIdentifier yangInstanceIdentifier, - final InstanceIdentifier instanceIdentifier, - final Collection dataObjects) { - final Collection> normalizedRootElements = Collections2 - .transform(dataObjects, toNormalizedNodeFunction(instanceIdentifier)); - - final DataSchemaNode schemaNode = - globalContext.getDataChildByName(yangInstanceIdentifier.getLastPathArgument().getNodeType()); - if (schemaNode instanceof ListSchemaNode) { - // In case of a list, wrap all the values in a Mixin parent node - final ListSchemaNode listSchema = (ListSchemaNode) schemaNode; - return wrapListIntoMixinNode(normalizedRootElements, listSchema); - } else { - Preconditions.checkState(dataObjects.size() == 1, "Singleton list was expected"); - return getOnlyElement(normalizedRootElements); - } - } - - private static DataContainerChild wrapListIntoMixinNode( - final Collection> normalizedRootElements, final ListSchemaNode listSchema) { - if (listSchema.getKeyDefinition().isEmpty()) { - final CollectionNodeBuilder listBuilder = - Builders.unkeyedListBuilder(); - for (NormalizedNode normalizedRootElement : normalizedRootElements) { - listBuilder.withChild((UnkeyedListEntryNode) normalizedRootElement); - } - return listBuilder.build(); - } else { - final CollectionNodeBuilder listBuilder = - listSchema.isUserOrdered() - ? Builders.orderedMapBuilder() - : Builders.mapBuilder(); - - for (NormalizedNode normalizedRootElement : normalizedRootElements) { - listBuilder.withChild((MapEntryNode) normalizedRootElement); - } - return listBuilder.build(); - } - } - - @SuppressWarnings("unchecked") - private Function> toNormalizedNodeFunction(final InstanceIdentifier path) { - return new Function>() { - @Override - public NormalizedNode apply(@Nullable final DataObject dataObject) { - LOG.trace("VppOperationalDataTree.toNormalizedNode(), path={}, dataObject={}", path, dataObject); - final Map.Entry> entry = - serializer.toNormalizedNode(path, dataObject); - - LOG.trace("VppOperationalDataTree.toNormalizedNode(), normalizedNodeEntry={}", entry); - return entry.getValue(); - } - }; - } - - private static final class ReadContextImpl implements ReadContext { - public final Context ctx = new Context(); - - @Nonnull - @Override - public Context getContext() { - return ctx; - } - - @Override - public void close() { - // Make sure to clear the storage in case some customizer stored it to prevent memory leaks - ctx.close(); - } - } -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppReadOnlyTransaction.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppReadOnlyTransaction.java deleted file mode 100644 index 94cef679f..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppReadOnlyTransaction.java +++ /dev/null @@ -1,103 +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.data; - -import com.google.common.base.Function; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -import com.google.common.util.concurrent.CheckedFuture; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -final class VppReadOnlyTransaction implements DOMDataReadOnlyTransaction { - - private static final Logger LOG = LoggerFactory.getLogger(VppReadOnlyTransaction.class); - private volatile ReadableVppDataTree operationalData; - private volatile VppDataTreeSnapshot configSnapshot; - - VppReadOnlyTransaction(@Nonnull final ReadableVppDataTree operationalData, - @Nonnull final VppDataTreeSnapshot configSnapshot) { - this.operationalData = Preconditions.checkNotNull(operationalData, "operationalData should not be null"); - this.configSnapshot = Preconditions.checkNotNull(configSnapshot, "config should not be null"); - } - - @Override - public void close() { - configSnapshot = null; - operationalData = null; - } - - @Override - public CheckedFuture>, ReadFailedException> read( - final LogicalDatastoreType store, - final YangInstanceIdentifier path) { - LOG.debug("VppReadOnlyTransaction.read(), store={}, path={}", store, path); - - Preconditions.checkState(configSnapshot != null, "Transaction was closed"); - - if (store == LogicalDatastoreType.OPERATIONAL) { - return operationalData.read(path); - } else { - return configSnapshot.read(path); - } - } - - @Override - public CheckedFuture exists(final LogicalDatastoreType store, - final YangInstanceIdentifier path) { - LOG.debug("VppReadOnlyTransaction.exists() store={}, path={}", store, path); - - ListenableFuture listenableFuture = Futures.transform(read(store, path), IS_NODE_PRESENT); - - return Futures.makeChecked(listenableFuture, ANY_EX_TO_READ_FAILED_EXCEPTION_MAPPER); - } - - @Nonnull - @Override - public Object getIdentifier() { - return this; - } - - - private static final Function>, ? extends Boolean> IS_NODE_PRESENT = - new Function>, Boolean>() { - @Nullable - @Override - public Boolean apply(@Nullable final Optional> input) { - return input == null - ? Boolean.FALSE - : input.isPresent(); - } - }; - - private static final Function ANY_EX_TO_READ_FAILED_EXCEPTION_MAPPER = - new Function() { - @Override - public ReadFailedException apply(@Nullable final Exception e) { - return new ReadFailedException("Exists failed", e); - } - }; -} \ No newline at end of file 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 deleted file mode 100644 index b33fffa68..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppWriteTransaction.java +++ /dev/null @@ -1,145 +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.data; - -import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.CANCELED; -import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.COMMITED; -import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.FAILED; -import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.NEW; -import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.SUBMITED; - -import com.google.common.base.Preconditions; -import com.google.common.util.concurrent.CheckedFuture; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; -import io.fd.honeycomb.v3po.translate.TranslationException; -import javax.annotation.Nonnull; -import javax.annotation.concurrent.NotThreadSafe; -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; -import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; -import org.opendaylight.yangtools.yang.common.RpcResult; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@NotThreadSafe -final class VppWriteTransaction implements DOMDataWriteTransaction { - - private static final Logger LOG = LoggerFactory.getLogger(VppWriteTransaction.class); - private final VppDataTree configDataTree; - private DataTreeModification modification; - private TransactionStatus status; - - VppWriteTransaction(@Nonnull final VppDataTree configDataTree, - @Nonnull final VppDataTreeSnapshot configSnapshot) { - this.configDataTree = Preconditions.checkNotNull(configDataTree, "configDataTree should not be null"); - Preconditions.checkNotNull(configSnapshot, "configSnapshot should not be null"); - // initialize transaction state: - modification = configSnapshot.newModification(); - status = NEW; - } - - VppWriteTransaction(@Nonnull final VppDataTree configDataTree) { - this(configDataTree, configDataTree.takeSnapshot()); - } - - private static void checkConfigurationWrite(final LogicalDatastoreType store) { - Preconditions.checkArgument(LogicalDatastoreType.CONFIGURATION == store, "Write is not supported for operational data store"); - } - - private void checkIsNew() { - Preconditions.checkState(status == NEW, "Transaction was submitted or canceled"); - Preconditions.checkState(modification != null, "VPPDataTree modification should not be null"); - } - - @Override - public void put(final LogicalDatastoreType store, final YangInstanceIdentifier path, - final NormalizedNode data) { - LOG.debug("VppWriteTransaction.put() store={}, path={}, data={}", store, path, data); - checkIsNew(); - checkConfigurationWrite(store); - modification.write(path, data); - } - - @Override - public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path, - final NormalizedNode data) { - LOG.debug("VppWriteTransaction.merge() store={}, path={}, data={}", store, path, data); - checkIsNew(); - checkConfigurationWrite(store); - modification.merge(path, data); - } - - @Override - public boolean cancel() { - if (status != NEW) { - // only NEW transactions can be cancelled - return false; - } else { - status = CANCELED; - modification = null; - return true; - } - } - - @Override - public void delete(LogicalDatastoreType store, final YangInstanceIdentifier path) { - LOG.debug("VppWriteTransaction.delete() store={}, path={}", store, path); - checkIsNew(); - checkConfigurationWrite(store); - modification.delete(path); - } - - @Override - public CheckedFuture submit() { - LOG.debug("VppWriteTransaction.submit()"); - checkIsNew(); - - // seal transaction: - modification.ready(); - status = SUBMITED; - - try { - configDataTree.commit(modification); - status = COMMITED; - } catch (DataValidationFailedException | TranslationException e) { - status = FAILED; - LOG.error("Failed to commit VPP state modification", e); - return Futures.immediateFailedCheckedFuture( - new TransactionCommitFailedException("Failed to validate DataTreeModification", e)); - } finally { - modification = null; - } - return Futures.immediateCheckedFuture(null); - } - - @Override - @Deprecated - public ListenableFuture> commit() { - throw new UnsupportedOperationException("deprecated"); - } - - @Override - public Object getIdentifier() { - return this; - } -} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/WriterRegistry.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/WriterRegistry.java deleted file mode 100644 index 00dc22520..000000000 --- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/WriterRegistry.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.data; - -import io.fd.honeycomb.v3po.translate.TranslationException; -import io.fd.honeycomb.v3po.translate.util.RWUtils; -import io.fd.honeycomb.v3po.translate.impl.write.CompositeChildWriter; -import io.fd.honeycomb.v3po.translate.impl.write.CompositeListWriter; -import io.fd.honeycomb.v3po.translate.impl.write.CompositeRootWriter; -import io.fd.honeycomb.v3po.translate.util.write.DelegatingWriterRegistry; -import io.fd.honeycomb.v3po.translate.util.write.NoopWriterCustomizer; -import io.fd.honeycomb.v3po.translate.util.write.ReflexiveChildWriterCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.vpp.BridgeDomainCustomizer; -import io.fd.honeycomb.v3po.translate.write.ChildWriter; -import io.fd.honeycomb.v3po.translate.write.Writer; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -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.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.openvpp.vppjapi.vppApi; - -// TODO use some DI framework instead of singleton -public class WriterRegistry implements io.fd.honeycomb.v3po.translate.write.WriterRegistry { - - private static WriterRegistry instance; - - private final DelegatingWriterRegistry writer; - - private WriterRegistry(@Nonnull final vppApi vppApi) { - final CompositeRootWriter vppWriter = initVppStateWriter(vppApi); - writer = new DelegatingWriterRegistry(Collections.>singletonList(vppWriter)); - } - - private static CompositeRootWriter initVppStateWriter(@Nonnull final vppApi vppApi) { - final CompositeListWriter bridgeDomainWriter = new CompositeListWriter<>( - BridgeDomain.class, - new BridgeDomainCustomizer(vppApi)); - - final ChildWriter bridgeDomainsWriter = new CompositeChildWriter<>( - BridgeDomains.class, - RWUtils.singletonChildWriterList(bridgeDomainWriter), - new ReflexiveChildWriterCustomizer()); - - final List>> childWriters = new ArrayList<>(); - childWriters.add(bridgeDomainsWriter); - - return new CompositeRootWriter<>( - Vpp.class, - childWriters, - new NoopWriterCustomizer()); - } - - public static synchronized WriterRegistry getInstance(@Nonnull final vppApi vppApi) { - if (instance == null) { - instance = new WriterRegistry(vppApi); - } - return instance; - } - - @Nonnull - @Override - public InstanceIdentifier getManagedDataObjectType() { - return writer.getManagedDataObjectType(); - } - - @Override - public void update(@Nonnull final InstanceIdentifier id, - @Nullable final DataObject dataBefore, - @Nullable final DataObject data, @Nonnull final WriteContext ctx) throws TranslationException { - writer.update(id, dataBefore, data, ctx); - } - - @Override - public void update(@Nonnull final Map, DataObject> dataBefore, - @Nonnull final Map, DataObject> dataAfter, - @Nonnull final WriteContext ctx) - throws TranslationException { - writer.update(dataBefore, dataAfter, ctx); - } -} diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/DataTreeUtilsTest.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/DataTreeUtilsTest.java deleted file mode 100644 index 7f1db5118..000000000 --- a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/DataTreeUtilsTest.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.data; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Map; -import org.junit.Test; -import org.mockito.Mockito; -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.ContainerNode; -import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; - -public class DataTreeUtilsTest { - - @Test - public void testChildrenFromNormalized() throws Exception { - final ContainerNode parent = mock(ContainerNode.class); - final BindingNormalizedNodeSerializer serializer = mock(BindingNormalizedNodeSerializer.class); - - final Collection list = new ArrayList<>(); - doReturn(list).when(parent).getValue(); - - // init child1 (will not be serialized) - final DataContainerChild child1 = Mockito.mock(DataContainerChild.class); - when(child1.getIdentifier()).thenReturn(mock(YangInstanceIdentifier.PathArgument.class)); - when(serializer.fromNormalizedNode(any(YangInstanceIdentifier.class), eq(child1))).thenReturn(null); - list.add(child1); - - // init child 2 (will be serialized) - final DataContainerChild child2 = mock(DataContainerChild.class); - when(child2.getIdentifier()).thenReturn(mock(YangInstanceIdentifier.PathArgument.class)); - - final Map.Entry entry = mock(Map.Entry.class); - final InstanceIdentifier id = mock(InstanceIdentifier.class); - doReturn(id).when(entry).getKey(); - final DataObject data = mock(DataObject.class); - doReturn(data).when(entry).getValue(); - when(serializer.fromNormalizedNode(any(YangInstanceIdentifier.class), eq(child2))).thenReturn(entry); - - list.add(child2); - - // run tested method - final Map, DataObject> map = DataTreeUtils.childrenFromNormalized(parent, serializer); - assertEquals(1, map.size()); - assertEquals(data, map.get(id)); - } -} \ No newline at end of file diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/ReadWriteTransactionTest.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/ReadWriteTransactionTest.java deleted file mode 100644 index f0fd66de5..000000000 --- a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/ReadWriteTransactionTest.java +++ /dev/null @@ -1,111 +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.data; - -import static org.junit.Assert.assertNotNull; -import static org.mockito.Mockito.verify; -import static org.mockito.MockitoAnnotations.initMocks; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; - -public class ReadWriteTransactionTest { - - @Mock - private DOMDataReadOnlyTransaction readTx; - - @Mock - private DOMDataWriteTransaction writeTx; - - private LogicalDatastoreType store; - - @Mock - private YangInstanceIdentifier path; - - @Mock - private NormalizedNode data; - - private ReadWriteTransaction readWriteTx; - - @Before - public void setUp() { - initMocks(this); - store = LogicalDatastoreType.CONFIGURATION; - readWriteTx = new ReadWriteTransaction(readTx, writeTx); - } - - @Test - public void testCancel() { - readWriteTx.cancel(); - verify(writeTx).cancel(); - } - - @Test - public void testPut() { - readWriteTx.put(store, path, data); - verify(writeTx).put(store, path, data); - } - - @Test - public void testMerge() { - readWriteTx.merge(store, path, data); - verify(writeTx).merge(store, path, data); - } - - @Test - public void testDelete() { - readWriteTx.delete(store, path); - verify(writeTx).delete(store, path); - } - - @Test - public void testSubmit() throws Exception { - readWriteTx.submit(); - verify(writeTx).submit(); - } - - - @SuppressWarnings("deprecation") - @Test - public void testCommit() throws Exception { - readWriteTx.commit(); - verify(writeTx).commit(); - } - - @Test - public void testRead() { - readWriteTx.read(store, path); - verify(readTx).read(store, path); - } - - @Test - public void testExists() { - readWriteTx.exists(store, path); - verify(readTx).exists(store, path); - } - - @Test - public void testGetIdentifier() throws Exception { - assertNotNull(readWriteTx.getIdentifier()); - } -} \ No newline at end of file diff --git a/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 deleted file mode 100644 index c4315cd38..000000000 --- a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VPPConfigDataTreeTest.java +++ /dev/null @@ -1,268 +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.data; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyMap; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import com.google.common.base.Optional; -import com.google.common.util.concurrent.CheckedFuture; -import io.fd.honeycomb.v3po.translate.TranslationException; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -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.ReadFailedException; -import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Ethernet; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; -import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot; - -public class VPPConfigDataTreeTest { - - @Mock - private WriterRegistry vppWriter; - @Mock - private BindingNormalizedNodeSerializer serializer; - @Mock - private DataTree dataTree; - @Mock - private DataTreeModification modification; - - private VppConfigDataTree proxy; - - @Before - public void setUp() { - initMocks(this); - proxy = new VppConfigDataTree(serializer, dataTree, vppWriter); - } - - @Test - public void testRead() throws Exception { - final DataTreeSnapshot snapshot = mock(DataTreeSnapshot.class); - when(dataTree.takeSnapshot()).thenReturn(snapshot); - - final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class); - final Optional node = mock(Optional.class); - doReturn(node).when(snapshot).readNode(path); - - final VppDataTreeSnapshot vppDataTreeSnapshot = proxy.takeSnapshot(); - final CheckedFuture>, ReadFailedException> future = - vppDataTreeSnapshot.read(path); - - verify(dataTree).takeSnapshot(); - verify(snapshot).readNode(path); - - assertTrue(future.isDone()); - assertEquals(node, future.get()); - } - - @Test - public void testNewModification() throws Exception { - final DataTreeSnapshot snapshot = mock(DataTreeSnapshot.class); - when(dataTree.takeSnapshot()).thenReturn(snapshot); - - when(snapshot.newModification()).thenReturn(modification); - - final VppDataTreeSnapshot vppDataTreeSnapshot = proxy.takeSnapshot(); - final DataTreeModification newModification = vppDataTreeSnapshot.newModification(); - verify(dataTree).takeSnapshot(); - verify(snapshot).newModification(); - - assertEquals(modification, newModification); - } - - @Test - public void testCommitSuccessful() throws Exception { - final DataObject dataBefore = mockDataObject("before", Ethernet.class); - final DataObject dataAfter = mockDataObject("after", Ethernet.class); - - // Prepare modification: - final DataTreeCandidateNode rootNode = mockRootNode(); - // data before: - final ContainerNode nodeBefore = mockContainerNode(dataBefore); - when(rootNode.getDataBefore()).thenReturn(Optional.>fromNullable(nodeBefore)); - // data after: - final ContainerNode nodeAfter = mockContainerNode(dataAfter); - when(rootNode.getDataAfter()).thenReturn(Optional.>fromNullable(nodeAfter)); - - // Run the test - proxy.commit(modification); - - // Verify all changes were processed: - verify(vppWriter).update( - mapOf(dataBefore, Ethernet.class), - mapOf(dataAfter, Ethernet.class), - any(WriteContext.class)); - - // Verify modification was validated - verify(dataTree).validate(modification); - } - - private Map, DataObject> mapOf(final DataObject dataBefore, final Class type) { - return eq( - Collections., DataObject>singletonMap(InstanceIdentifier.create(type), - dataBefore)); - } - - private DataObject mockDataObject(final String name, final Class classToMock) { - final DataObject dataBefore = mock(classToMock, name); - doReturn(classToMock).when(dataBefore).getImplementedInterface(); - return dataBefore; - } - - @Test - public void testCommitUndoSuccessful() throws Exception { - // Prepare data changes: - final DataObject dataBefore = mockDataObject("before", Ethernet.class); - final DataObject dataAfter = mockDataObject("after", Ethernet.class); - - final io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter reverter = mock( - io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.class); - - // Fail on update: - final TranslationException failedOnUpdateException = new TranslationException("update failed"); - doThrow(new io.fd.honeycomb.v3po.translate.write.WriterRegistry.BulkUpdateException(InstanceIdentifier.create(Ethernet.class), reverter, - failedOnUpdateException)).when(vppWriter).update(anyMap(), anyMap(), any(WriteContext.class)); - - // Prepare modification: - final DataTreeCandidateNode rootNode = mockRootNode(); - // data before: - final ContainerNode nodeBefore = mockContainerNode(dataBefore); - when(rootNode.getDataBefore()).thenReturn(Optional.>fromNullable(nodeBefore)); - // data after: - final ContainerNode nodeAfter = mockContainerNode(dataAfter); - when(rootNode.getDataAfter()).thenReturn(Optional.>fromNullable(nodeAfter)); - - // Run the test - try { - proxy.commit(modification); - } catch (io.fd.honeycomb.v3po.translate.write.WriterRegistry.BulkUpdateException e) { - verify(vppWriter).update(anyMap(), anyMap(), any(WriteContext.class)); - verify(reverter).revert(); - assertEquals(failedOnUpdateException, e.getCause()); - return; - } - - fail("WriterRegistry.BulkUpdateException was expected"); - } - - @Test - public void testCommitUndoFailed() throws Exception { - // Prepare data changes: - final DataObject dataBefore = mockDataObject("before", Ethernet.class); - final DataObject dataAfter = mockDataObject("after", Ethernet.class); - - final io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter reverter = mock( - io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.class); - - // Fail on update: - doThrow(new io.fd.honeycomb.v3po.translate.write.WriterRegistry.BulkUpdateException(InstanceIdentifier.create(Ethernet.class), reverter, - new TranslationException("update failed"))).when(vppWriter).update(anyMap(), anyMap(), any(WriteContext.class)); - - // Fail on revert: - final TranslationException failedOnRevertException = new TranslationException("update failed"); - final io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.RevertFailedException revertFailedException = - new io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.RevertFailedException(Collections.>emptyList(), - failedOnRevertException); - doThrow(revertFailedException).when(reverter).revert(); - - // Prepare modification: - final DataTreeCandidateNode rootNode = mockRootNode(); - // data before: - final ContainerNode nodeBefore = mockContainerNode(dataBefore); - when(rootNode.getDataBefore()).thenReturn(Optional.>fromNullable(nodeBefore)); - // data after: - final ContainerNode nodeAfter = mockContainerNode(dataAfter); - when(rootNode.getDataAfter()).thenReturn(Optional.>fromNullable(nodeAfter)); - - // Run the test - try { - proxy.commit(modification); - } catch (io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.RevertFailedException e) { - verify(vppWriter).update(anyMap(), anyMap(), any(WriteContext.class)); - verify(reverter).revert(); - assertEquals(failedOnRevertException, e.getCause()); - return; - } - - fail("RevertFailedException was expected"); - } - - private DataTreeCandidateNode mockRootNode() { - final DataTreeCandidate candidate = mock(DataTreeCandidate.class); - when(dataTree.prepare(modification)).thenReturn(candidate); - - final DataTreeCandidateNode rootNode = mock(DataTreeCandidateNode.class); - when(candidate.getRootNode()).thenReturn(rootNode); - - return rootNode; - } - - private ContainerNode mockContainerNode(DataObject... modifications) { - final int numberOfChildren = modifications.length; - - final YangInstanceIdentifier.NodeIdentifier identifier = - YangInstanceIdentifier.NodeIdentifier.create(QName.create("/")); - - final ContainerNode node = mock(ContainerNode.class); - when(node.getIdentifier()).thenReturn(identifier); - - final List list = new ArrayList<>(numberOfChildren); - doReturn(list).when(node).getValue(); - - for (DataObject modification : modifications) { - final DataContainerChild child = mock(DataContainerChild.class); - when(child.getIdentifier()).thenReturn(mock(YangInstanceIdentifier.PathArgument.class)); - list.add(child); - - final Map.Entry entry = mock(Map.Entry.class); - final Class implementedInterface = - (Class) modification.getImplementedInterface(); - final InstanceIdentifier id = InstanceIdentifier.create(implementedInterface); - - doReturn(id).when(entry).getKey(); - doReturn(modification).when(entry).getValue(); - doReturn(entry).when(serializer).fromNormalizedNode(any(YangInstanceIdentifier.class), eq(child)); - } - return node; - } -} 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 51f57a252..770ca7068 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,6 +26,8 @@ import static org.mockito.Mockito.verify; import static org.mockito.MockitoAnnotations.initMocks; import com.google.common.util.concurrent.CheckedFuture; +import io.fd.honeycomb.v3po.config.WriterRegistry; +import io.fd.honeycomb.v3po.impl.VppDataBrokerInitializationProvider; import io.fd.honeycomb.v3po.translate.read.ReaderRegistry; import org.junit.Before; import org.junit.Test; diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerTest.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerTest.java deleted file mode 100644 index 2550f458b..000000000 --- a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerTest.java +++ /dev/null @@ -1,108 +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.data; - -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import java.util.Map; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener; -import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension; -import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; - -public class VppDataBrokerTest { - - @Mock - private ReadableVppDataTree operationalData; - @Mock - private VppDataTree confiDataTree; - @Mock - private VppDataTreeSnapshot configSnapshot; - private VppDataBroker broker; - - @Before - public void setUp() { - initMocks(this); - when(confiDataTree.takeSnapshot()).thenReturn(configSnapshot); - broker = new VppDataBroker(operationalData, confiDataTree); - } - - @Test - public void testNewReadWriteTransaction() { - final DOMDataReadWriteTransaction readWriteTx = broker.newReadWriteTransaction(); - final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class); - readWriteTx.read(LogicalDatastoreType.CONFIGURATION, path); - - // verify that read and write transactions use the same config snapshot - verify(configSnapshot).read(path); - verify(configSnapshot).newModification(); - } - - @Test - public void testNewWriteOnlyTransaction() { - final DOMDataWriteTransaction writeTx = broker.newWriteOnlyTransaction(); - - // verify that write transactions use config snapshot - verify(configSnapshot).newModification(); - } - - @Test - public void testNewReadOnlyTransaction() { - final DOMDataReadOnlyTransaction readTx = broker.newReadOnlyTransaction(); - - final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class); - readTx.read(LogicalDatastoreType.CONFIGURATION, path); - - // verify that read transactions use config snapshot - verify(configSnapshot).read(path); - } - - @Test(expected = UnsupportedOperationException.class) - public void testRegisterDataChangeListener() { - final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class); - final DOMDataChangeListener listener = mock(DOMDataChangeListener.class); - broker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, path, listener, - AsyncDataBroker.DataChangeScope.BASE); - } - - @Test(expected = UnsupportedOperationException.class) - public void testCreateTransactionChain() { - final TransactionChainListener listener = mock(TransactionChainListener.class); - broker.createTransactionChain(listener); - } - - @Test - public void testGetSupportedExtensions() { - final Map, DOMDataBrokerExtension> supportedExtensions = - broker.getSupportedExtensions(); - assertTrue(supportedExtensions.isEmpty()); - } - - -} \ No newline at end of file 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 deleted file mode 100644 index 049c2a0c8..000000000 --- a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppOperationalDataTreeTest.java +++ /dev/null @@ -1,171 +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.data; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.same; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import com.google.common.base.Optional; -import com.google.common.collect.Iterables; -import com.google.common.collect.LinkedListMultimap; -import com.google.common.collect.Multimap; -import com.google.common.util.concurrent.CheckedFuture; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReaderRegistry; -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.ReadFailedException; -import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer; -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; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; -import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; - -public class VppOperationalDataTreeTest { - - @Mock - private BindingNormalizedNodeSerializer serializer; - @Mock - private ReaderRegistry reader; - - private VppOperationalDataTree operationalData; - - @Mock - private InstanceIdentifier id; - @Mock - private Map.Entry> entry; - @Mock - private SchemaContext globalContext; - @Mock - private DataSchemaNode schemaNode; - @Mock - private ReadContext readCtx; - - @Before - public void setUp() { - initMocks(this); - operationalData = new VppOperationalDataTree(serializer, globalContext, reader); - doReturn(schemaNode).when(globalContext).getDataChildByName(any(QName.class)); - } - - @Test - public void testReadNode() throws Exception { - final YangInstanceIdentifier yangId = mock(YangInstanceIdentifier.class); - final YangInstanceIdentifier.PathArgument pArg = mock(YangInstanceIdentifier.PathArgument.class); - doReturn(pArg).when(yangId).getLastPathArgument(); - - doReturn(QName.create("namespace", "2012-12-12", "local")).when(pArg).getNodeType(); - doReturn(id).when(serializer).fromYangInstanceIdentifier(yangId); - - final DataObject dataObject = mock(DataObject.class); - doReturn(Optional.of(dataObject)).when(reader).read(same(id), any(ReadContext.class)); - - when(serializer.toNormalizedNode(id, dataObject)).thenReturn(entry); - final DataContainerChild expectedValue = mock(DataContainerChild.class); - doReturn(expectedValue).when(entry).getValue(); - - final CheckedFuture>, ReadFailedException> future = operationalData.read(yangId); - - verify(serializer).fromYangInstanceIdentifier(yangId); - verify(reader).read(same(id), any(ReadContext.class)); - final Optional> result = future.get(); - assertTrue(result.isPresent()); - assertEquals(expectedValue, result.get()); - } - - @Test - public void testReadNonExistingNode() throws Exception { - final YangInstanceIdentifier yangId = mock(YangInstanceIdentifier.class); - doReturn(id).when(serializer).fromYangInstanceIdentifier(yangId); - doReturn(Optional.absent()).when(reader).read(same(id), any(ReadContext.class)); - - final CheckedFuture>, ReadFailedException> future = operationalData.read(yangId); - - verify(serializer).fromYangInstanceIdentifier(yangId); - verify(reader).read(same(id), any(ReadContext.class)); - final Optional> result = future.get(); - assertFalse(result.isPresent()); - } - - @Test - public void testReadFailed() throws Exception{ - doThrow(io.fd.honeycomb.v3po.translate.read.ReadFailedException.class).when(reader).readAll(any(ReadContext.class)); - - final CheckedFuture>, ReadFailedException> future = - operationalData.read( YangInstanceIdentifier.EMPTY); - - try { - future.checkedGet(); - } catch (ReadFailedException e) { - assertTrue(e.getCause() instanceof io.fd.honeycomb.v3po.translate.read.ReadFailedException); - return; - } - fail("ReadFailedException was expected"); - } - - @Test - public void testReadRootWithOneNonListElement() throws Exception { - // Prepare data - final InstanceIdentifier vppStateII = InstanceIdentifier.create(VppState.class); - final VppState vppState = mock(VppState.class); - Multimap, DataObject> dataObjects = LinkedListMultimap.create(); - dataObjects.put(vppStateII, vppState); - doReturn(dataObjects).when(reader).readAll(any(ReadContext.class)); - - // Init serializer - final YangInstanceIdentifier vppYangId = YangInstanceIdentifier.builder().node(VppState.QNAME).build(); - when(serializer.toYangInstanceIdentifier(vppStateII)).thenReturn(vppYangId); - when(serializer.toNormalizedNode(vppStateII, vppState)).thenReturn(entry); - final DataContainerChild vppStateContainer = mock(DataContainerChild.class); - doReturn(vppStateContainer).when(entry).getValue(); - doReturn(vppYangId.getLastPathArgument()).when(vppStateContainer).getIdentifier(); - - // Read root - final CheckedFuture>, ReadFailedException> future = - operationalData.read(YangInstanceIdentifier.EMPTY); - - verify(reader).readAll(any(ReadContext.class)); - verify(serializer).toYangInstanceIdentifier(vppStateII); - verify(serializer).toNormalizedNode(vppStateII, vppState); - - // Check the result is an ContainerNode with only one child - final Optional> result = future.get(); - assertTrue(result.isPresent()); - - final ContainerNode rootNode = (ContainerNode) result.get(); - assertEquals(SchemaContext.NAME, rootNode.getIdentifier().getNodeType()); - assertEquals(vppStateContainer, Iterables.getOnlyElement(rootNode.getValue())); - } -} \ No newline at end of file diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppReadOnlyTransactionTest.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppReadOnlyTransactionTest.java deleted file mode 100644 index 5a8a1f72b..000000000 --- a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppReadOnlyTransactionTest.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.data; - -import static org.junit.Assert.assertNotNull; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import com.google.common.base.Optional; -import com.google.common.util.concurrent.CheckedFuture; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; - -public class VppReadOnlyTransactionTest { - - @Mock - private ReadableVppDataTree operationalData; - @Mock - private VppDataTreeSnapshot configSnapshot; - - private VppReadOnlyTransaction readOnlyTx; - - @Before - public void setUp() { - initMocks(this); - readOnlyTx = new VppReadOnlyTransaction(operationalData, configSnapshot); - } - - @Test - public void testExists() { - final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class); - final CheckedFuture>, ReadFailedException> - future = mock(CheckedFuture.class); - when(operationalData.read(path)).thenReturn(future); - - readOnlyTx.exists(LogicalDatastoreType.OPERATIONAL, path); - - verify(operationalData).read(path); - } - - @Test - public void testGetIdentifier() { - assertNotNull(readOnlyTx.getIdentifier()); - } -} \ No newline at end of file diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppWriteTransactionTest.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppWriteTransactionTest.java deleted file mode 100644 index 905224216..000000000 --- a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppWriteTransactionTest.java +++ /dev/null @@ -1,134 +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.data; - -import static junit.framework.TestCase.assertTrue; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import com.google.common.util.concurrent.CheckedFuture; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException; - -public class VppWriteTransactionTest { - - @Mock - private VppDataTree configDataTree; - @Mock - private VppDataTreeSnapshot configSnapshot; - @Mock - private YangInstanceIdentifier path; - @Mock - private NormalizedNode data; - @Mock - private DataTreeModification dataTreeModification; - - private VppWriteTransaction writeTx; - - @Before - public void setUp() { - initMocks(this); - when(configSnapshot.newModification()).thenReturn(dataTreeModification); - writeTx = new VppWriteTransaction(configDataTree, configSnapshot); - } - - @Test - public void testPut() { - writeTx.put(LogicalDatastoreType.CONFIGURATION, path, data); - verify(dataTreeModification).write(path, data); - } - - @Test(expected = IllegalArgumentException.class) - public void testPutOperational() { - writeTx.put(LogicalDatastoreType.OPERATIONAL, path, data); - verify(dataTreeModification).write(path, data); - } - - @Test(expected = IllegalStateException.class) - public void testOnFinishedTx() { - writeTx.submit(); - writeTx.put(LogicalDatastoreType.CONFIGURATION, path, data); - verify(dataTreeModification).write(path, data); - } - - @Test - public void testMerge() { - writeTx.merge(LogicalDatastoreType.CONFIGURATION, path, data); - verify(dataTreeModification).merge(path, data); - } - - @Test - public void testCancel() { - assertTrue(writeTx.cancel()); - } - - @Test - public void testCancelFinished() { - writeTx.submit(); - assertFalse(writeTx.cancel()); - } - - @Test - public void testDelete() { - writeTx.delete(LogicalDatastoreType.CONFIGURATION, path); - verify(dataTreeModification).delete(path); - } - - @Test - public void testSubmit() throws Exception { - writeTx.submit(); - verify(dataTreeModification).ready(); - verify(configDataTree).commit(dataTreeModification); - } - - @Test - public void testSubmitFailed() throws Exception { - doThrow(mock(DataValidationFailedException.class)).when(configDataTree).commit(dataTreeModification); - final CheckedFuture future = writeTx.submit(); - try { - future.get(); - } catch (Exception e) { - assertTrue(e.getCause() instanceof TransactionCommitFailedException); - return; - } - fail("Expected exception to be thrown"); - - } - - @Test(expected = UnsupportedOperationException.class) - public void testCommit() { - writeTx.commit(); - } - - @Test - public void testGetIdentifier() { - assertNotNull(writeTx.getIdentifier()); - } -} \ No newline at end of file diff --git a/v3po/pom.xml b/v3po/pom.xml index 7fdf97b44..7ec5d708a 100644 --- a/v3po/pom.xml +++ b/v3po/pom.xml @@ -33,6 +33,9 @@ api + config + data-api + data-impl translate-spi translate-api translate-impl -- cgit 1.2.3-korg