diff options
16 files changed, 419 insertions, 120 deletions
diff --git a/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/HoneycombWriteInfraTest.java b/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/HoneycombWriteInfraTest.java index a740e0121..54b93c768 100644 --- a/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/HoneycombWriteInfraTest.java +++ b/infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/HoneycombWriteInfraTest.java @@ -22,6 +22,7 @@ import static org.mockito.Matchers.eq; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; @@ -29,6 +30,7 @@ import static org.mockito.Mockito.when; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import io.fd.honeycomb.data.DataModification; +import io.fd.honeycomb.test.model.Ids; import io.fd.honeycomb.translate.impl.write.registry.FlatWriterRegistryBuilder; import io.fd.honeycomb.translate.util.YangDAG; import io.fd.honeycomb.translate.write.WriteContext; @@ -40,6 +42,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import org.junit.Test; import org.mockito.InOrder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ComplexAugment; @@ -75,7 +79,6 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.data.api.schema.tree.TipProducingDataTree; import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType; import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory; -import io.fd.honeycomb.test.model.Ids; /** * Testing honeycomb writes from data tree up to mocked writers. @@ -103,6 +106,31 @@ public class HoneycombWriteInfraTest extends AbstractInfraTest { private static <D extends DataObject> Writer<D> mockWriter(final InstanceIdentifier<D> id) { final Writer<D> mock = (Writer<D>) mock(Writer.class); when(mock.getManagedDataObjectType()).thenReturn(id); + //TODO - HONEYCOMB-412 - to call default impl of canProcess() + when(mock.canProcess(any())).thenAnswer(invocationOnMock -> { + final Writer writer = Writer.class.cast(invocationOnMock.getMock()); + final Writer delegatingWriter = new Writer() { + @Nonnull + @Override + public InstanceIdentifier getManagedDataObjectType() { + return writer.getManagedDataObjectType(); + } + + @Override + public boolean supportsDirectUpdate() { + return writer.supportsDirectUpdate(); + } + + @Override + public void processModification(@Nonnull final InstanceIdentifier id, + @Nullable final DataObject dataBefore, + @Nullable final DataObject dataAfter, @Nonnull final WriteContext ctx) + throws WriteFailedException { + writer.processModification(id, dataBefore, dataAfter, ctx); + } + }; + return delegatingWriter.canProcess(InstanceIdentifier.class.cast(invocationOnMock.getArguments()[0])); + }); return mock; } @@ -226,8 +254,19 @@ public class HoneycombWriteInfraTest extends AbstractInfraTest { for (Writer<?> orderedWriter : orderedWriters) { verify(orderedWriter).getManagedDataObjectType(); - verifyNoMoreInteractions(orderedWriter); + //TODO - HONEYCOMB-412 + //verifyNoMoreInteractions(orderedWriter); } + + verify(complexAugmentContainerWriter, times(1)).processModification(any(), any(), any(), any()); + verify(c3Writer, times(1)).processModification(any(), any(), any(), any()); + verify(simpleAugmentWriter, times(1)).processModification(any(), any(), any(), any()); + verify(simpleContainerWriter, times(1)).processModification(any(), any(), any(), any()); + verify(containerWithChoiceWriter, times(1)).processModification(any(), any(), any(), any()); + verify(containerFromGroupingWriter, times(1)).processModification(any(), any(), any(), any()); + verify(nestedListWriter, times(2)).processModification(any(), any(), any(), any()); + verify(listInContainerWriter, times(2)).processModification(any(), any(), any(), any()); + verify(containerInListWriter, times(2)).processModification(any(), any(), any(), any()); } private Writer<?>[] getOrderedWriters() { @@ -316,8 +355,19 @@ public class HoneycombWriteInfraTest extends AbstractInfraTest { for (Writer<?> orderedWriter : orderedWriters) { verify(orderedWriter).getManagedDataObjectType(); - verifyNoMoreInteractions(orderedWriter); + //TODO - HONEYCOMB-412 + // verifyNoMoreInteractions(orderedWriter); } + + verify(complexAugmentContainerWriter, times(2)).processModification(any(), any(), any(), any()); + verify(c3Writer, times(2)).processModification(any(), any(), any(), any()); + verify(simpleAugmentWriter, times(2)).processModification(any(), any(), any(), any()); + verify(simpleContainerWriter, times(2)).processModification(any(), any(), any(), any()); + verify(containerWithChoiceWriter, times(2)).processModification(any(), any(), any(), any()); + verify(containerFromGroupingWriter, times(2)).processModification(any(), any(), any(), any()); + verify(nestedListWriter, times(4)).processModification(any(), any(), any(), any()); + verify(listInContainerWriter, times(4)).processModification(any(), any(), any(), any()); + verify(containerInListWriter, times(4)).processModification(any(), any(), any(), any()); } private void writeContainerWithList(final DataModification dataModification) { diff --git a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/schema/YangModulesProvider.java b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/schema/YangModulesProvider.java index b60df1ad6..5acc1ea08 100644 --- a/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/schema/YangModulesProvider.java +++ b/infra/minimal-distribution-core/src/main/java/io/fd/honeycomb/infra/distro/schema/YangModulesProvider.java @@ -56,10 +56,10 @@ public class YangModulesProvider implements Provider<YangModulesProvider.YangMod .collect(Collectors.toSet())); } - public static class YangModules { + static class YangModules { private final Set<Class<? extends YangModelBindingProvider>> yangBindings; - public YangModules(final Set<Class<? extends YangModelBindingProvider>> yangBindings) { + YangModules(final Set<Class<? extends YangModelBindingProvider>> yangBindings) { this.yangBindings = yangBindings; } diff --git a/infra/northbound/bgp/src/main/java/io/fd/honeycomb/infra/bgp/ApplicationRibWriterFactory.java b/infra/northbound/bgp/src/main/java/io/fd/honeycomb/infra/bgp/ApplicationRibWriterFactory.java index 02f1788f3..00a12e7ac 100644 --- a/infra/northbound/bgp/src/main/java/io/fd/honeycomb/infra/bgp/ApplicationRibWriterFactory.java +++ b/infra/northbound/bgp/src/main/java/io/fd/honeycomb/infra/bgp/ApplicationRibWriterFactory.java @@ -45,14 +45,6 @@ final class ApplicationRibWriterFactory implements WriterFactory { InstanceIdentifier.create(ApplicationRib.class); private static final InstanceIdentifier<Tables> TABLES_IID = AR_IID.child(Tables.class); - - // TODO (HONEYCOMB-359): - // BGP models are huge, we need some kind of wildcarded subtree writer, that works for whole subtree. - // 1) we can either move checking handledTypes to writers (getHandledTypes, isAffected, writer.getHandedTypes, ...) - // but then precondition check in flatWriterRegistry might be slower (we need to check if we have all writers - // in order to avoid unnecessary reverts). - // - // 2) alternative is to compute all child nodes during initialization (might introduce some footprint penalty). @Override public void init(final ModifiableWriterRegistryBuilder registry) { registry.subtreeAdd(ImmutableSet.of(TABLES_IID), new BindingBrokerWriter<>(InstanceIdentifier.create(ApplicationRib.class), dataBroker) diff --git a/infra/northbound/bgp/src/main/java/io/fd/honeycomb/infra/bgp/neighbors/BgpPeerWriterFactory.java b/infra/northbound/bgp/src/main/java/io/fd/honeycomb/infra/bgp/neighbors/BgpPeerWriterFactory.java index 8b7510eb8..848b4d504 100644 --- a/infra/northbound/bgp/src/main/java/io/fd/honeycomb/infra/bgp/neighbors/BgpPeerWriterFactory.java +++ b/infra/northbound/bgp/src/main/java/io/fd/honeycomb/infra/bgp/neighbors/BgpPeerWriterFactory.java @@ -16,21 +16,14 @@ package io.fd.honeycomb.infra.bgp.neighbors; -import com.google.common.collect.Sets; import com.google.inject.Inject; import io.fd.honeycomb.infra.bgp.BgpConfiguration; import io.fd.honeycomb.translate.impl.write.GenericListWriter; import io.fd.honeycomb.translate.write.WriterFactory; import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder; -import javax.annotation.Nonnull; import org.opendaylight.protocol.bgp.openconfig.spi.BGPTableTypeRegistryConsumer; import org.opendaylight.protocol.bgp.rib.impl.spi.BGPPeerRegistry; import org.opendaylight.protocol.bgp.rib.impl.spi.RIB; -import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.multiprotocol.rev151009.bgp.common.afi.safi.list.AfiSafi; -import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.AfiSafis; -import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.Config; -import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.Timers; -import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.Transport; import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbors.Neighbor; import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.Bgp; import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Neighbors; @@ -38,25 +31,24 @@ import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.re import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.NetworkInstance; import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.Protocols; import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.protocols.Protocol; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev160614.AfiSafi1; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev160614.Config1; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev160614.Config2; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev160614.Protocol1; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import javax.annotation.Nonnull; + /** * Initializes writer for Bgp Neighbors ({@link Neighbor} node) and all its parents required by HC infra. */ public final class BgpPeerWriterFactory implements WriterFactory { private static final InstanceIdentifier<NetworkInstance> NETWORK_INSTANCE_ID = - InstanceIdentifier.create(NetworkInstances.class) - .child(NetworkInstance.class); + InstanceIdentifier.create(NetworkInstances.class) + .child(NetworkInstance.class); private static final InstanceIdentifier<Protocol> PROTOCOL_ID = - NETWORK_INSTANCE_ID.child(Protocols.class).child(Protocol.class); + NETWORK_INSTANCE_ID.child(Protocols.class).child(Protocol.class); private static final InstanceIdentifier<Neighbor> NEIGHBOR_ID = - PROTOCOL_ID.augmentation(Protocol1.class).child(Bgp.class).child(Neighbors.class).child(Neighbor.class); + PROTOCOL_ID.augmentation(Protocol1.class).child(Bgp.class).child(Neighbors.class).child(Neighbor.class); @Inject private BgpConfiguration configuration; @@ -72,39 +64,18 @@ public final class BgpPeerWriterFactory implements WriterFactory { // NetworkInstances // NetworkInstance = registry.add(new GenericListWriter<>(NETWORK_INSTANCE_ID, - new NetworkInstanceCustomizer(configuration.bgpNetworkInstanceName))); + new NetworkInstanceCustomizer(configuration.bgpNetworkInstanceName))); // Protocols // Protocol = registry.add( - new GenericListWriter<>(PROTOCOL_ID, new ProtocolCustomizer(configuration.bgpProtocolInstanceName.get()))); + new GenericListWriter<>(PROTOCOL_ID, new ProtocolCustomizer(configuration.bgpProtocolInstanceName.get()))); // Protocol1 augmentation (from bgp-openconfig-extensions) // Bgp // Neighbors // Neighbor= - final InstanceIdentifier<Neighbor> neighbor = InstanceIdentifier.create(Neighbor.class); - registry.subtreeAdd( - // TODO (HONEYCOMB-359): there might be more subnodes that needs to be handled - Sets.newHashSet( - neighbor.child(Config.class), - neighbor.child(Config.class).augmentation(Config2.class), - neighbor.child(AfiSafis.class), - neighbor.child(AfiSafis.class).child(AfiSafi.class), - neighbor.child(AfiSafis.class).child(AfiSafi.class).augmentation(AfiSafi1.class), - neighbor.child(Timers.class), - neighbor.child(Timers.class).child( - org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.timers.Config.class), - neighbor.child(Transport.class), - neighbor.child(Transport.class).child( - org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.transport.Config.class), - neighbor.child(Transport.class).child( - org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.transport.Config.class) - .augmentation(Config1.class) - ), - new GenericListWriter<>( - NEIGHBOR_ID, - new NeighborCustomizer(globalRib, peerRegistry, tableTypeRegistry))); + registry.wildcardedSubtreeAdd(new GenericListWriter<>(NEIGHBOR_ID, new NeighborCustomizer(globalRib, peerRegistry, tableTypeRegistry))); } } diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/translate/ModifiableSubtreeManagerRegistryBuilder.java b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/ModifiableSubtreeManagerRegistryBuilder.java index 4e6b2d805..ad9cd2b6f 100644 --- a/infra/translate-api/src/main/java/io/fd/honeycomb/translate/ModifiableSubtreeManagerRegistryBuilder.java +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/ModifiableSubtreeManagerRegistryBuilder.java @@ -16,12 +16,13 @@ package io.fd.honeycomb.translate; -import java.util.Collection; -import java.util.Set; -import javax.annotation.Nonnull; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import javax.annotation.Nonnull; +import java.util.Collection; +import java.util.Set; + /** * Registry builder where {@link SubtreeManager}s can be added with or without relationships between them. * The relationships express what the order of execution should be. @@ -42,6 +43,11 @@ public interface ModifiableSubtreeManagerRegistryBuilder<S extends SubtreeManage @Nonnull S handler); /** + * Add a handler responsible for writing all complex nodes within a subtree its responsible for. + */ + ModifiableSubtreeManagerRegistryBuilder<S> wildcardedSubtreeAdd(@Nonnull S handler); + + /** * Add a handler and make sure it will be executed before handler identifier by relatedType is executed. */ ModifiableSubtreeManagerRegistryBuilder<S> addBefore(@Nonnull S handler, @@ -50,6 +56,12 @@ public interface ModifiableSubtreeManagerRegistryBuilder<S extends SubtreeManage ModifiableSubtreeManagerRegistryBuilder<S> addBefore(@Nonnull S handler, @Nonnull Collection<InstanceIdentifier<?>> relatedTypes); + ModifiableSubtreeManagerRegistryBuilder<S> wildcardedSubtreeAddBefore(@Nonnull S handler, + @Nonnull InstanceIdentifier<?> relatedType); + + ModifiableSubtreeManagerRegistryBuilder<S> wildcardedSubtreeAddBefore(@Nonnull S handler, + @Nonnull Collection<InstanceIdentifier<?>> relatedTypes); + ModifiableSubtreeManagerRegistryBuilder<S> subtreeAddBefore(@Nonnull Set<InstanceIdentifier<?>> handledChildren, @Nonnull S handler, @Nonnull InstanceIdentifier<?> relatedType); @@ -67,6 +79,12 @@ public interface ModifiableSubtreeManagerRegistryBuilder<S extends SubtreeManage ModifiableSubtreeManagerRegistryBuilder<S> addAfter(@Nonnull S handler, @Nonnull Collection<InstanceIdentifier<?>> relatedTypes); + ModifiableSubtreeManagerRegistryBuilder<S> wildcardedSubtreeAddAfter(@Nonnull S handler, + @Nonnull InstanceIdentifier<?> relatedType); + + ModifiableSubtreeManagerRegistryBuilder<S> wildcardedSubtreeAddAfter(@Nonnull S handler, + @Nonnull Collection<InstanceIdentifier<?>> relatedTypes); + ModifiableSubtreeManagerRegistryBuilder<S> subtreeAddAfter(@Nonnull Set<InstanceIdentifier<?>> handledChildren, @Nonnull S handler, @Nonnull InstanceIdentifier<?> relatedType); diff --git a/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/Writer.java b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/Writer.java index 1a16b72e6..18573e58a 100644 --- a/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/Writer.java +++ b/infra/translate-api/src/main/java/io/fd/honeycomb/translate/write/Writer.java @@ -47,8 +47,17 @@ public interface Writer<D extends DataObject> extends SubtreeManager<D> { @Nonnull final WriteContext ctx) throws WriteFailedException; /** - * Indicates whether there is direct support for updating nodes handled by this writer, + * Indicates whether there is direct support for updating nodes handled by writer, * or they must be broken up to individual deletes and creates. */ boolean supportsDirectUpdate(); + + /** + * Returns true if node identified by this identifier can be processes by this writer + * + * @param instanceIdentifier identifier to be checked + */ + default boolean canProcess(@Nonnull final InstanceIdentifier<? extends DataObject> instanceIdentifier) { + return getManagedDataObjectType().equals(instanceIdentifier); + } } diff --git a/infra/translate-impl/pom.xml b/infra/translate-impl/pom.xml index c11893a1b..aa2a48b19 100644 --- a/infra/translate-impl/pom.xml +++ b/infra/translate-impl/pom.xml @@ -53,6 +53,12 @@ <type>test-jar</type> <scope>test</scope> </dependency> + <dependency> + <groupId>io.fd.honeycomb.it</groupId> + <artifactId>honeycomb-test-model</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> <dependency> <groupId>junit</groupId> @@ -69,6 +75,12 @@ <artifactId>hamcrest-all</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-simple</artifactId> + <version>1.7.25</version> + <scope>test</scope> + </dependency> </dependencies> <build> diff --git a/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/read/registry/CompositeReaderRegistryBuilder.java b/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/read/registry/CompositeReaderRegistryBuilder.java index f8290f166..4f7e1e140 100644 --- a/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/read/registry/CompositeReaderRegistryBuilder.java +++ b/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/read/registry/CompositeReaderRegistryBuilder.java @@ -16,8 +16,6 @@ package io.fd.honeycomb.translate.impl.read.registry; -import static com.google.common.base.Preconditions.checkArgument; - import com.google.common.collect.ImmutableMap; import io.fd.honeycomb.translate.impl.read.GenericListReader; import io.fd.honeycomb.translate.impl.read.GenericReader; @@ -29,12 +27,6 @@ import io.fd.honeycomb.translate.read.registry.ReaderRegistry; import io.fd.honeycomb.translate.read.registry.ReaderRegistryBuilder; import io.fd.honeycomb.translate.util.AbstractSubtreeManagerRegistryBuilderBuilder; import io.fd.honeycomb.translate.util.YangDAG; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import javax.annotation.concurrent.NotThreadSafe; import org.opendaylight.yangtools.concepts.Builder; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.Identifiable; @@ -43,6 +35,15 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.Nonnull; +import javax.annotation.concurrent.NotThreadSafe; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkArgument; + @NotThreadSafe public final class CompositeReaderRegistryBuilder extends AbstractSubtreeManagerRegistryBuilderBuilder<Reader<? extends DataObject, ? extends Builder<?>>, ReaderRegistry> @@ -63,6 +64,11 @@ public final class CompositeReaderRegistryBuilder } @Override + protected Reader<? extends DataObject, ? extends Builder<?>> getWildcardedSubtreeHandler(@Nonnull Reader<? extends DataObject, ? extends Builder<?>> handler) { + throw new UnsupportedOperationException("Wildcarded readers are not supported"); + } + + @Override public <D extends DataObject> void addStructuralReader(@Nonnull InstanceIdentifier<D> id, @Nonnull Class<? extends Builder<D>> builderType) { // prevent case to submit structural reader for list, which would cause fail because target setter consumes diff --git a/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/registry/FlatWriterRegistry.java b/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/registry/FlatWriterRegistry.java index 146ddb9c5..c3bc1ee0e 100644 --- a/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/registry/FlatWriterRegistry.java +++ b/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/registry/FlatWriterRegistry.java @@ -21,7 +21,6 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.base.Optional; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; @@ -32,12 +31,15 @@ import io.fd.honeycomb.translate.write.WriteContext; import io.fd.honeycomb.translate.write.Writer; import io.fd.honeycomb.translate.write.registry.UpdateFailedException; import io.fd.honeycomb.translate.write.registry.WriterRegistry; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.annotation.concurrent.ThreadSafe; @@ -54,39 +56,23 @@ final class FlatWriterRegistry implements WriterRegistry { private static final Logger LOG = LoggerFactory.getLogger(FlatWriterRegistry.class); - // All types handled by writers directly or as children - private final ImmutableSet<InstanceIdentifier<?>> handledTypes; - private final Set<InstanceIdentifier<?>> writersOrderReversed; private final Set<InstanceIdentifier<?>> writersOrder; - private final Map<InstanceIdentifier<?>, Writer<?>> writers; + private final Map<InstanceIdentifier<?>, Writer<?>> writersById; + private final Set<? extends Writer<?>> writers; /** * Create flat registry instance. * - * @param writers immutable, ordered map of writers to use to process updates. Order of the writers has to be one in + * @param writersById immutable, ordered map of writers to use to process updates. Order of the writers has to be one in * which create and update operations should be handled. Deletes will be handled in reversed order. * All deletes are handled before handling all the updates. */ - FlatWriterRegistry(@Nonnull final ImmutableMap<InstanceIdentifier<?>, Writer<?>> writers) { - this.writers = writers; - this.writersOrderReversed = Sets.newLinkedHashSet(Lists.reverse(Lists.newArrayList(writers.keySet()))); - this.writersOrder = writers.keySet(); - this.handledTypes = getAllHandledTypes(writers); - } - - private static ImmutableSet<InstanceIdentifier<?>> getAllHandledTypes( - @Nonnull final ImmutableMap<InstanceIdentifier<?>, Writer<?>> writers) { - final ImmutableSet.Builder<InstanceIdentifier<?>> handledTypesBuilder = ImmutableSet.builder(); - for (Map.Entry<InstanceIdentifier<?>, Writer<?>> writerEntry : writers.entrySet()) { - final InstanceIdentifier<?> writerType = writerEntry.getKey(); - final Writer<?> writer = writerEntry.getValue(); - handledTypesBuilder.add(writerType); - if (writer instanceof SubtreeWriter) { - handledTypesBuilder.addAll(((SubtreeWriter<?>) writer).getHandledChildTypes()); - } - } - return handledTypesBuilder.build(); + FlatWriterRegistry(@Nonnull final ImmutableMap<InstanceIdentifier<?>, Writer<?>> writersById) { + this.writersById = writersById; + this.writersOrderReversed = Sets.newLinkedHashSet(Lists.reverse(Lists.newArrayList(writersById.keySet()))); + this.writersOrder = writersById.keySet(); + this.writers = writersById.entrySet().stream().map(Map.Entry::getValue).collect(Collectors.toSet()); } @Override @@ -145,9 +131,9 @@ final class FlatWriterRegistry implements WriterRegistry { if (writer == null) { // This node must be handled by a subtree writer, find it and call it or else fail - checkArgument(handledTypes.contains(singleType), "Unable to process update. Missing writers for: %s", - singleType); writer = getSubtreeWriterResponsible(singleType); + checkArgument(writer != null, "Unable to process update. Missing writers for: %s", + singleType); singleTypeUpdates = getParentDataObjectUpdate(ctx, updates, writer); } @@ -168,9 +154,9 @@ final class FlatWriterRegistry implements WriterRegistry { @Nullable private Writer<?> getSubtreeWriterResponsible(final InstanceIdentifier<?> singleType) { - return writers.values().stream() + return writersById.values().stream() .filter(w -> w instanceof SubtreeWriter) - .filter(w -> ((SubtreeWriter<?>) w).getHandledChildTypes().contains(singleType)) + .filter(w -> w.canProcess(singleType)) .findFirst() .orElse(null); } @@ -249,10 +235,23 @@ final class FlatWriterRegistry implements WriterRegistry { private void checkAllTypesCanBeHandled( @Nonnull final Multimap<InstanceIdentifier<?>, ? extends DataObjectUpdate> updates) { - if (!handledTypes.containsAll(updates.keySet())) { - final Sets.SetView<InstanceIdentifier<?>> missingWriters = Sets.difference(updates.keySet(), handledTypes); - LOG.warn("Unable to process update. Missing writers for: {}", missingWriters); - throw new IllegalArgumentException("Unable to process update. Missing writers for: " + missingWriters); + + List<InstanceIdentifier<?>> noWriterNodes = new ArrayList<>(); + for (InstanceIdentifier<?> id : updates.keySet()) { + // either there is direct writer for the iid + if (writersById.containsKey(id)) { + continue; + } else { + // or subtree one + if (writers.stream().anyMatch(o -> o.canProcess(id))) { + continue; + } + } + noWriterNodes.add(id); + } + + if (!noWriterNodes.isEmpty()) { + throw new IllegalArgumentException("Unable to process update. Missing writers for: " + noWriterNodes); } } @@ -269,7 +268,7 @@ final class FlatWriterRegistry implements WriterRegistry { @Nullable private Writer<?> getWriter(@Nonnull final InstanceIdentifier<?> singleType) { - return writers.get(singleType); + return writersById.get(singleType); } } diff --git a/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/registry/FlatWriterRegistryBuilder.java b/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/registry/FlatWriterRegistryBuilder.java index 0c6d0a1b4..43606064e 100644 --- a/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/registry/FlatWriterRegistryBuilder.java +++ b/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/registry/FlatWriterRegistryBuilder.java @@ -24,15 +24,16 @@ import io.fd.honeycomb.translate.write.Writer; import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder; import io.fd.honeycomb.translate.write.registry.WriterRegistry; import io.fd.honeycomb.translate.write.registry.WriterRegistryBuilder; -import java.util.Set; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import javax.annotation.concurrent.NotThreadSafe; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.Nonnull; +import javax.annotation.concurrent.NotThreadSafe; +import java.util.Set; +import java.util.stream.Collectors; + /** * Builder for {@link FlatWriterRegistry} allowing users to specify inter-writer relationships. */ @@ -53,6 +54,11 @@ public final class FlatWriterRegistryBuilder return SubtreeWriter.createForWriter(handledChildren, writer); } + @Override + protected Writer<? extends DataObject> getWildcardedSubtreeHandler(@Nonnull Writer<? extends DataObject> handler) { + return SubtreeWriter.createWildcardedForWriter(handler); + } + /** * Create FlatWriterRegistry with writers ordered according to submitted relationships. */ diff --git a/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/registry/SubtreeWriter.java b/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/registry/SubtreeWriter.java index b2a571b40..a1a5f3fd0 100644 --- a/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/registry/SubtreeWriter.java +++ b/infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/registry/SubtreeWriter.java @@ -37,15 +37,16 @@ final class SubtreeWriter<D extends DataObject> implements Writer<D> { private final Writer<D> delegate; private final Set<InstanceIdentifier<?>> handledChildTypes = new HashSet<>(); + private boolean isWildcarded = false; - private SubtreeWriter(final Writer<D> delegate, Set<InstanceIdentifier<?>> handledTypes) { + private SubtreeWriter(final Writer<D> delegate, final Set<InstanceIdentifier<?>> handledTypes) { this.delegate = delegate; for (InstanceIdentifier<?> handledType : handledTypes) { // Iid has to start with writer's handled root type checkArgument(delegate.getManagedDataObjectType().getTargetType().equals( handledType.getPathArguments().iterator().next().getType()), "Handled node from subtree has to be identified by an instance identifier starting from: %s." - + "Instance identifier was: %s", getManagedDataObjectType().getTargetType(), handledType); + + "Instance identifier was: %s", getManagedDataObjectType().getTargetType(), handledType); checkArgument(Iterables.size(handledType.getPathArguments()) > 1, "Handled node from subtree identifier too short: %s", handledType); handledChildTypes.add(InstanceIdentifier.create(Iterables.concat( @@ -53,6 +54,11 @@ final class SubtreeWriter<D extends DataObject> implements Writer<D> { } } + private SubtreeWriter(final Writer<D> delegate) { + this.delegate = delegate; + this.isWildcarded = true; + } + /** * Return set of types also handled by this writer. All of the types are children of the type managed by this * writer excluding the type of this writer. @@ -75,6 +81,20 @@ final class SubtreeWriter<D extends DataObject> implements Writer<D> { } @Override + public boolean canProcess(@Nonnull InstanceIdentifier<?> instanceIdentifier) { + if (isWildcarded) { + final Class<D> parent = delegate.getManagedDataObjectType().getTargetType(); + for (InstanceIdentifier.PathArgument pathArgument : instanceIdentifier.getPathArguments()) { + if (pathArgument.getType().equals(parent)) { + return true; + } + } + return false; + } + return handledChildTypes.contains(instanceIdentifier); + } + + @Override @Nonnull public InstanceIdentifier<D> getManagedDataObjectType() { return delegate.getManagedDataObjectType(); @@ -87,4 +107,11 @@ final class SubtreeWriter<D extends DataObject> implements Writer<D> { @Nonnull final Writer<? extends DataObject> writer) { return new SubtreeWriter<>(writer, handledChildren); } + + /** + * Wrap a writer as a subtree writer. + */ + static Writer<?> createWildcardedForWriter(@Nonnull final Writer<? extends DataObject> writer) { + return new SubtreeWriter<>(writer); + } } diff --git a/infra/translate-impl/src/test/java/io/fd/honeycomb/translate/impl/write/registry/FlatWriterRegistryTest.java b/infra/translate-impl/src/test/java/io/fd/honeycomb/translate/impl/write/registry/FlatWriterRegistryTest.java index 151436975..01852d13f 100644 --- a/infra/translate-impl/src/test/java/io/fd/honeycomb/translate/impl/write/registry/FlatWriterRegistryTest.java +++ b/infra/translate-impl/src/test/java/io/fd/honeycomb/translate/impl/write/registry/FlatWriterRegistryTest.java @@ -25,6 +25,7 @@ import static org.mockito.Matchers.any; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyZeroInteractions; @@ -39,15 +40,19 @@ import io.fd.honeycomb.translate.util.DataObjects.DataObject1; import io.fd.honeycomb.translate.util.DataObjects.DataObject2; import io.fd.honeycomb.translate.write.DataObjectUpdate; import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; import io.fd.honeycomb.translate.write.Writer; import io.fd.honeycomb.translate.write.registry.UpdateFailedException; import io.fd.honeycomb.translate.write.registry.WriterRegistry; import java.util.List; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import org.junit.Before; import org.junit.Test; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.mockito.stubbing.Answer; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; @@ -72,6 +77,18 @@ public class FlatWriterRegistryTest { when(writer1.getManagedDataObjectType()).thenReturn(DataObject1.IID); when(writer2.getManagedDataObjectType()).thenReturn(DataObject2.IID); when(writer3.getManagedDataObjectType()).thenReturn(DataObjects.DataObject3.IID); + when(writer4.getManagedDataObjectType()).thenReturn(DataObjects.DataObject1ChildK.IID); + // TODO - HONEYCOMB-412 - thenCallRealMethod doest work with default methods + // https://stackoverflow.com/questions/27663252/can-you-make-mockito-1-10-17-work-with-default-methods-in-interfaces + when(writer1.canProcess(any())).thenAnswer(answerWithImpl()); + when(writer2.canProcess(any())).thenAnswer(answerWithImpl()); + when(writer3.canProcess(any())).thenAnswer(answerWithImpl()); + when(writer4.canProcess(any())).thenAnswer(answerWithImpl()); + } + + private static Answer<Object> answerWithImpl() { + return invocationOnMock -> new CheckedMockWriter(Writer.class.cast(invocationOnMock.getMock())).canProcess( + InstanceIdentifier.class.cast(invocationOnMock.getArguments()[0])); } @Test @@ -112,8 +129,12 @@ public class FlatWriterRegistryTest { inOrder.verify(writer1).processModification(iid, dataObject, dataObject, ctx); inOrder.verify(writer2).processModification(iid2, dataObject2, dataObject2, ctx); - verifyNoMoreInteractions(writer1); - verifyNoMoreInteractions(writer2); + // TODO - HONEYCOMB-412 -reintroduce verifyNoMoreInteractions and remove manual verify + // we are really interested just in invocations of processModification(),so adding specific verify to check that + verify(writer1,times(1)).processModification(any(),any(),any(),any()); + verify(writer2,times(1)).processModification(any(),any(),any(),any()); + //verifyNoMoreInteractions(writer1); + //verifyNoMoreInteractions(writer2); } @Test @@ -136,8 +157,12 @@ public class FlatWriterRegistryTest { inOrder.verify(writer2).processModification(iid2, dataObject2, null, ctx); inOrder.verify(writer1).processModification(iid, dataObject, null, ctx); - verifyNoMoreInteractions(writer1); - verifyNoMoreInteractions(writer2); + // TODO - HONEYCOMB-412 -reintroduce verifyNoMoreInteractions and remove manual verify + // we are really interested just in invocations of processModification(),so adding specific verify to check that + verify(writer1,times(1)).processModification(any(),any(),any(),any()); + verify(writer2,times(1)).processModification(any(),any(),any(),any()); + //verifyNoMoreInteractions(writer1); + //verifyNoMoreInteractions(writer2); } @Test @@ -170,8 +195,12 @@ public class FlatWriterRegistryTest { inOrder.verify(writer1).processModification(iid, dataObject, dataObject, ctx); inOrder.verify(writer2).processModification(iid2, dataObject2, dataObject2, ctx); - verifyNoMoreInteractions(writer1); - verifyNoMoreInteractions(writer2); + // TODO - HONEYCOMB-412 -reintroduce verifyNoMoreInteractions and remove manual verify + // we are really interested just in invocations of processModification(),so adding specific verify to check that + verify(writer1,times(2)).processModification(any(),any(),any(),any()); + verify(writer2,times(2)).processModification(any(),any(),any(),any()); + //verifyNoMoreInteractions(writer1); + //verifyNoMoreInteractions(writer2); } @Test(expected = IllegalArgumentException.class) @@ -298,4 +327,35 @@ public class FlatWriterRegistryTest { final InstanceIdentifier<D> iid) { return DataObjectUpdate.create(iid, mock(type), mock(type)); } + + //TODO - HONEYCOMB-412 - remove after + /** + * Used to utilize default implementation of canProcess() + * */ + static class CheckedMockWriter implements Writer{ + + private final Writer mockedWriter; + + CheckedMockWriter(final Writer mockedWriter) { + this.mockedWriter = mockedWriter; + } + + @Override + public void processModification(@Nonnull final InstanceIdentifier id, @Nullable final DataObject dataBefore, + @Nullable final DataObject dataAfter, @Nonnull final WriteContext ctx) + throws WriteFailedException { + mockedWriter.processModification(id,dataBefore,dataAfter,ctx); + } + + @Override + public boolean supportsDirectUpdate() { + return mockedWriter.supportsDirectUpdate(); + } + + @Nonnull + @Override + public InstanceIdentifier getManagedDataObjectType() { + return mockedWriter.getManagedDataObjectType(); + } + } }
\ No newline at end of file diff --git a/infra/translate-impl/src/test/java/io/fd/honeycomb/translate/impl/write/registry/WildcardedSubtreeWriterTest.java b/infra/translate-impl/src/test/java/io/fd/honeycomb/translate/impl/write/registry/WildcardedSubtreeWriterTest.java new file mode 100644 index 000000000..7006eeaf4 --- /dev/null +++ b/infra/translate-impl/src/test/java/io/fd/honeycomb/translate/impl/write/registry/WildcardedSubtreeWriterTest.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2017 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.translate.impl.write.registry; + +import io.fd.honeycomb.translate.write.Writer; +import org.junit.Before; +import org.junit.Test; +import org.mockito.MockitoAnnotations; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.aug.test.rev161222.AugTarget; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.aug.test.rev161222.FromAugmentAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.aug.test.rev161222.FromAugmentListAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.aug.test.rev161222.SimpleNestedAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.aug.test.rev161222.aug.target.FromAugment; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.aug.test.rev161222.aug.target.from.augment.FromAugmentEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithChoice; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.choice.choice.c3.C3; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainer; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.container.in.list.NestedList; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class WildcardedSubtreeWriterTest { + + private static final InstanceIdentifier<ContainerWithList> C_WITH_LIST = InstanceIdentifier.create(ContainerWithList.class); + private static final InstanceIdentifier<ContainerWithChoice> C_WITH_CHOICE = InstanceIdentifier.create(ContainerWithChoice.class); + private static final InstanceIdentifier<AugTarget> C_AUG = InstanceIdentifier.create(AugTarget.class); + + private static final InstanceIdentifier<ListInContainer> L_IN_CONTAINER = C_WITH_LIST.child(ListInContainer.class); + private static final InstanceIdentifier<ContainerInList> C_IN_LIST = L_IN_CONTAINER.child(ContainerInList.class); + + private static final InstanceIdentifier<NestedList> N_LIST = C_IN_LIST.child(NestedList.class); + + private Writer subtreeContainerWithList; + private Writer subtreeContainerWithChoice; + private Writer subtreeAugTarget; + + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + Writer<ContainerWithList> writerContainerWithList = mock(Writer.class); + Writer<ContainerWithChoice> writerContainerWithChoice = mock(Writer.class); + Writer<AugTarget> writerAugTarget = mock(Writer.class); + when(writerContainerWithList.getManagedDataObjectType()).thenReturn(C_WITH_LIST); + when(writerContainerWithChoice.getManagedDataObjectType()).thenReturn(C_WITH_CHOICE); + when(writerAugTarget.getManagedDataObjectType()).thenReturn(C_AUG); + subtreeContainerWithList = SubtreeWriter.createWildcardedForWriter(writerContainerWithList); + subtreeContainerWithChoice = SubtreeWriter.createWildcardedForWriter(writerContainerWithChoice); + subtreeAugTarget = SubtreeWriter.createWildcardedForWriter(writerAugTarget); + } + + @Test + public void testParent() { + assertTrue(subtreeContainerWithList.canProcess(C_WITH_LIST)); + assertFalse(subtreeContainerWithList.canProcess(C_WITH_CHOICE)); + + assertTrue(subtreeContainerWithChoice.canProcess(C_WITH_CHOICE)); + assertFalse(subtreeContainerWithChoice.canProcess(C_WITH_LIST)); + + assertTrue(subtreeAugTarget.canProcess(C_AUG)); + assertFalse(subtreeAugTarget.canProcess(C_WITH_LIST)); + } + + @Test + public void testDirectChild() { + assertTrue(subtreeContainerWithList.canProcess(L_IN_CONTAINER)); + assertFalse(subtreeContainerWithList.canProcess(C_WITH_CHOICE.child(C3.class))); + + assertTrue(subtreeContainerWithChoice.canProcess(C_WITH_CHOICE.child(C3.class))); + assertFalse(subtreeContainerWithChoice.canProcess(L_IN_CONTAINER)); + } + + @Test + public void testIndirectChild() { + assertTrue(subtreeContainerWithList.canProcess(C_IN_LIST)); + assertTrue(subtreeContainerWithList.canProcess(N_LIST)); + } + + @Test + public void testAugDirectChild() { + assertTrue(subtreeAugTarget.canProcess(C_AUG.augmentation(FromAugmentAugment.class).child(FromAugment.class))); + assertFalse(subtreeContainerWithList.canProcess(C_AUG.augmentation(FromAugmentAugment.class).child(FromAugment.class))); + } + + @Test + public void testAugIndirectChild() { + assertTrue(subtreeAugTarget.canProcess(C_AUG.augmentation(FromAugmentAugment.class) + .child(FromAugment.class) + .augmentation(SimpleNestedAugment.class))); + assertFalse(subtreeContainerWithList.canProcess(C_AUG.augmentation(FromAugmentAugment.class) + .child(FromAugment.class) + .augmentation(FromAugmentListAugment.class) + .child(FromAugmentEntry.class))); + } +} diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/AbstractSubtreeManagerRegistryBuilderBuilder.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/AbstractSubtreeManagerRegistryBuilderBuilder.java index fe2f1178f..181d71727 100644 --- a/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/AbstractSubtreeManagerRegistryBuilderBuilder.java +++ b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/AbstractSubtreeManagerRegistryBuilderBuilder.java @@ -21,13 +21,14 @@ import com.google.common.collect.ImmutableMap; import io.fd.honeycomb.translate.ModifiableSubtreeManagerRegistryBuilder; import io.fd.honeycomb.translate.SubtreeManager; import io.fd.honeycomb.translate.SubtreeManagerRegistryBuilder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import javax.annotation.Nonnull; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; -import javax.annotation.Nonnull; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; public abstract class AbstractSubtreeManagerRegistryBuilderBuilder<S extends SubtreeManager<? extends DataObject>, R> implements ModifiableSubtreeManagerRegistryBuilder<S>, SubtreeManagerRegistryBuilder<R> { @@ -64,6 +65,12 @@ public abstract class AbstractSubtreeManagerRegistryBuilderBuilder<S extends Sub return this; } + @Override + public ModifiableSubtreeManagerRegistryBuilder<S> wildcardedSubtreeAdd(@Nonnull S handler) { + add(getWildcardedSubtreeHandler(handler)); + return this; + } + private void checkWriterNotPresentYet(final InstanceIdentifier<?> targetType) { Preconditions.checkArgument(!handlersMap.containsKey(targetType), "Writer for type: %s already present: %s", targetType, handlersMap.get(targetType)); @@ -110,6 +117,12 @@ public abstract class AbstractSubtreeManagerRegistryBuilderBuilder<S extends Sub } @Override + public ModifiableSubtreeManagerRegistryBuilder<S> wildcardedSubtreeAddBefore(@Nonnull final S handler, + @Nonnull final InstanceIdentifier<?> relatedType) { + return addBefore(getWildcardedSubtreeHandler(handler), relatedType); + } + + @Override public AbstractSubtreeManagerRegistryBuilderBuilder<S, R> subtreeAddBefore( @Nonnull final Set<InstanceIdentifier<?>> handledChildren, @Nonnull final S handler, @@ -117,9 +130,17 @@ public abstract class AbstractSubtreeManagerRegistryBuilderBuilder<S extends Sub return addBefore(getSubtreeHandler(handledChildren, handler), relatedTypes); } + @Override + public ModifiableSubtreeManagerRegistryBuilder<S> wildcardedSubtreeAddBefore(@Nonnull final S handler, + @Nonnull final Collection<InstanceIdentifier<?>> relatedTypes) { + return addBefore(getWildcardedSubtreeHandler(handler), relatedTypes); + } + protected abstract S getSubtreeHandler(@Nonnull final Set<InstanceIdentifier<?>> handledChildren, @Nonnull final S handler); + protected abstract S getWildcardedSubtreeHandler(@Nonnull final S handler); + /** * Add handler with relationship: to be executed after handler handling relatedType. */ @@ -163,6 +184,12 @@ public abstract class AbstractSubtreeManagerRegistryBuilderBuilder<S extends Sub } @Override + public ModifiableSubtreeManagerRegistryBuilder<S> wildcardedSubtreeAddAfter(@Nonnull final S handler, + @Nonnull final InstanceIdentifier<?> relatedType) { + return addAfter(getWildcardedSubtreeHandler(handler), relatedType); + } + + @Override public AbstractSubtreeManagerRegistryBuilderBuilder<S, R> subtreeAddAfter( @Nonnull final Set<InstanceIdentifier<?>> handledChildren, @Nonnull final S handler, @@ -170,6 +197,11 @@ public abstract class AbstractSubtreeManagerRegistryBuilderBuilder<S extends Sub return addAfter(getSubtreeHandler(handledChildren, handler), relatedTypes); } + @Override + public ModifiableSubtreeManagerRegistryBuilder<S> wildcardedSubtreeAddAfter(@Nonnull S handler, @Nonnull Collection<InstanceIdentifier<?>> relatedTypes) { + return addAfter(getWildcardedSubtreeHandler(handler), relatedTypes); + } + protected ImmutableMap<InstanceIdentifier<?>, S> getMappedHandlers() { final ImmutableMap.Builder<InstanceIdentifier<?>, S> builder = ImmutableMap.builder(); // Iterate writer types according to their relationships from graph diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/AbstractGenericWriter.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/AbstractGenericWriter.java index e2ea11535..4f1b696cf 100644 --- a/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/AbstractGenericWriter.java +++ b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/AbstractGenericWriter.java @@ -16,19 +16,20 @@ package io.fd.honeycomb.translate.util.write; -import static com.google.common.base.Preconditions.checkArgument; - import io.fd.honeycomb.translate.util.RWUtils; import io.fd.honeycomb.translate.write.WriteContext; import io.fd.honeycomb.translate.write.WriteFailedException; import io.fd.honeycomb.translate.write.Writer; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkArgument; + public abstract class AbstractGenericWriter<D extends DataObject> implements Writer<D> { private static final Logger LOG = LoggerFactory.getLogger(AbstractGenericWriter.class); diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/BindingBrokerWriter.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/BindingBrokerWriter.java index 7b68376ba..60a81a77a 100644 --- a/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/BindingBrokerWriter.java +++ b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/write/BindingBrokerWriter.java @@ -16,20 +16,21 @@ package io.fd.honeycomb.translate.util.write; -import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION; - import com.google.common.util.concurrent.CheckedFuture; import io.fd.honeycomb.translate.write.WriteContext; import io.fd.honeycomb.translate.write.WriteFailedException; import io.fd.honeycomb.translate.write.Writer; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION; + /** * Simple DataBroker backed writer allowing to delegate writes to different brokers. */ |