Move ordering logic out of AbstractSubtreeManagerRegistryBuilderBuilder 57/7057/3
authorMarek Gradzki <mgradzki@cisco.com>
Thu, 8 Jun 2017 10:18:08 +0000 (12:18 +0200)
committerMarek Gradzki <mgradzki@cisco.com>
Fri, 9 Jun 2017 05:19:26 +0000 (07:19 +0200)
Introduces YangDAG that maintains topological order for yang schema
nodes and can be used by other components to read additional graph edges,
e.g. from file (HONEYCOMB-365).

Change-Id: Ia3046d38ffb4ca222412309f6c4391afc9315bd2
Signed-off-by: Marek Gradzki <mgradzki@cisco.com>
14 files changed:
infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/HoneycombReadInfraTest.java
infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/HoneycombSubtreeReadInfraTest.java
infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/HoneycombWriteInfraTest.java
infra/it/it-test/src/test/java/io/fd/honeycomb/data/impl/NestedAugmentationWriteTest.java
infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/data/config/WriterRegistryProvider.java
infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/data/oper/ReaderRegistryBuilderProvider.java [deleted file]
infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/data/oper/ReaderRegistryProvider.java
infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/read/registry/CompositeReaderRegistryBuilder.java
infra/translate-impl/src/main/java/io/fd/honeycomb/translate/impl/write/registry/FlatWriterRegistryBuilder.java
infra/translate-impl/src/test/java/io/fd/honeycomb/translate/impl/read/registry/CompositeReaderRegistryBuilderTest.java
infra/translate-impl/src/test/java/io/fd/honeycomb/translate/impl/write/registry/FlatWriterRegistryBuilderTest.java
infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/AbstractSubtreeManagerRegistryBuilderBuilder.java
infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/YangDAG.java [new file with mode: 0644]
infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/YangDAGTest.java [new file with mode: 0644]

index 143317b..53fd2e9 100644 (file)
 
 package io.fd.honeycomb.data.impl;
 
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyListOf;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.atMost;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
 import com.google.common.base.Optional;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Multimap;
@@ -28,15 +44,27 @@ import io.fd.honeycomb.translate.read.ReadContext;
 import io.fd.honeycomb.translate.read.ReadFailedException;
 import io.fd.honeycomb.translate.read.Reader;
 import io.fd.honeycomb.translate.read.registry.ReaderRegistry;
+import io.fd.honeycomb.translate.util.YangDAG;
 import io.fd.honeycomb.translate.util.RWUtils;
 import io.fd.honeycomb.translate.util.read.ReflexiveListReaderCustomizer;
 import io.fd.honeycomb.translate.util.read.ReflexiveReaderCustomizer;
+import java.lang.reflect.InvocationTargetException;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
 import org.junit.Test;
 import org.mockito.InOrder;
 import org.mockito.Mock;
 import org.mockito.exceptions.misusing.MockitoConfigurationException;
 import org.mockito.invocation.InvocationOnMock;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ComplexAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ComplexAugmentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleAugmentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleContainer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleContainerBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainer;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainerBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainerKey;
@@ -55,20 +83,7 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 
-import javax.annotation.Nonnull;
-import java.lang.reflect.InvocationTargetException;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.*;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyListOf;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.*;
-
 public class HoneycombReadInfraTest extends AbstractInfraTest {
-
     @Mock
     private ReadContext ctx;
     private ReaderRegistry registry;
@@ -108,7 +123,7 @@ public class HoneycombReadInfraTest extends AbstractInfraTest {
     }
 
     private void initReaderRegistry() {
-        registry = new CompositeReaderRegistryBuilder()
+        registry = new CompositeReaderRegistryBuilder(new YangDAG())
                 .add(containerWithListReader) // 2
                 .addBefore(simpleContainerReader, Ids.CONTAINER_WITH_LIST_ID) // 1
                 .add(simpleAugmentReader) // 1.1
index b513b58..b586a18 100644 (file)
@@ -26,18 +26,15 @@ import com.google.common.collect.Multimap;
 import com.google.common.collect.Sets;
 import com.google.common.util.concurrent.CheckedFuture;
 import io.fd.honeycomb.translate.impl.read.GenericListReader;
+import io.fd.honeycomb.translate.impl.read.registry.CompositeReaderRegistryBuilder;
 import io.fd.honeycomb.translate.read.ListReader;
 import io.fd.honeycomb.translate.read.ReadContext;
 import io.fd.honeycomb.translate.read.ReadFailedException;
 import io.fd.honeycomb.translate.read.Reader;
 import io.fd.honeycomb.translate.read.registry.ReaderRegistry;
+import io.fd.honeycomb.translate.util.YangDAG;
 import io.fd.honeycomb.translate.util.read.ReflexiveListReaderCustomizer;
-import io.fd.honeycomb.translate.impl.read.registry.CompositeReaderRegistryBuilder;
-
-import java.util.Collections;
-import java.util.List;
 import java.util.stream.Collectors;
-import javax.annotation.Nonnull;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithList;
@@ -85,7 +82,7 @@ public class HoneycombSubtreeReadInfraTest extends AbstractInfraTest {
     }
 
     private void initReaderRegistry() {
-        registry = new CompositeReaderRegistryBuilder()
+        registry = new CompositeReaderRegistryBuilder(new YangDAG())
                 // Subtree reader handling its child list
                 .subtreeAdd(Sets.newHashSet(Ids.LIST_IN_CONTAINER_ID), containerWithListReader)
                 // Reflexive
index bd51e39..b98c912 100644 (file)
@@ -30,8 +30,9 @@ import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import io.fd.honeycomb.data.DataModification;
 import io.fd.honeycomb.translate.impl.write.registry.FlatWriterRegistryBuilder;
-import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.honeycomb.translate.util.YangDAG;
 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.WriterRegistry;
 import java.util.ArrayList;
@@ -116,7 +117,7 @@ public class HoneycombWriteInfraTest extends AbstractInfraTest {
     }
 
     private void initWriterRegistry() {
-        writerRegistry = new FlatWriterRegistryBuilder()
+        writerRegistry = new FlatWriterRegistryBuilder(new YangDAG())
                 .add(complexAugmentWriter) // unordered
                 .add(nestedListWriter) // 6
                 .addAfter(listInContainerWriter, Ids.NESTED_LIST_ID) // 7
@@ -473,7 +474,7 @@ public class HoneycombWriteInfraTest extends AbstractInfraTest {
 
     @Test
     public void testSubtreeWriter() throws Exception {
-        writerRegistry = new FlatWriterRegistryBuilder()
+        writerRegistry = new FlatWriterRegistryBuilder(new YangDAG())
                 // Handles also container from grouping
                 .subtreeAdd(Sets.newHashSet(Ids.CONTAINER_FROM_GROUPING_ID), containerWithChoiceWriter)
                 .build();
index 351b88e..3b7d4a1 100644 (file)
@@ -25,6 +25,7 @@ import static org.mockito.Mockito.when;
 
 import io.fd.honeycomb.data.DataModification;
 import io.fd.honeycomb.translate.impl.write.registry.FlatWriterRegistryBuilder;
+import io.fd.honeycomb.translate.util.YangDAG;
 import io.fd.honeycomb.translate.write.WriteContext;
 import io.fd.honeycomb.translate.write.Writer;
 import io.fd.honeycomb.translate.write.registry.WriterRegistry;
@@ -132,7 +133,7 @@ public class NestedAugmentationWriteTest extends AbstractInfraTest {
     }
 
     private void initWriterRegistry() {
-        writerRegistry = new FlatWriterRegistryBuilder()
+        writerRegistry = new FlatWriterRegistryBuilder(new YangDAG())
             .add(augTargetWriter)
             .add(fromAugmentWriter)
             .add(listFromAugmentWriter)
index e368266..6546ba2 100644 (file)
@@ -19,6 +19,7 @@ package io.fd.honeycomb.infra.distro.data.config;
 import com.google.inject.Inject;
 import io.fd.honeycomb.infra.distro.ProviderTrait;
 import io.fd.honeycomb.translate.impl.write.registry.FlatWriterRegistryBuilder;
+import io.fd.honeycomb.translate.util.YangDAG;
 import io.fd.honeycomb.translate.write.WriterFactory;
 import io.fd.honeycomb.translate.write.registry.WriterRegistry;
 import java.util.HashSet;
@@ -31,7 +32,7 @@ public final class WriterRegistryProvider extends ProviderTrait<WriterRegistry>
 
     @Override
     protected WriterRegistry create() {
-        final FlatWriterRegistryBuilder builder = new FlatWriterRegistryBuilder();
+        final FlatWriterRegistryBuilder builder = new FlatWriterRegistryBuilder(new YangDAG());
         writerFactories
                 .stream()
                 .forEach(it -> it.init(builder));
diff --git a/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/data/oper/ReaderRegistryBuilderProvider.java b/infra/minimal-distribution/src/main/java/io/fd/honeycomb/infra/distro/data/oper/ReaderRegistryBuilderProvider.java
deleted file mode 100644 (file)
index ab967e1..0000000
+++ /dev/null
@@ -1,40 +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.infra.distro.data.oper;
-
-import com.google.inject.Inject;
-import io.fd.honeycomb.infra.distro.ProviderTrait;
-import io.fd.honeycomb.translate.read.ReaderFactory;
-import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder;
-import io.fd.honeycomb.translate.impl.read.registry.CompositeReaderRegistryBuilder;
-import java.util.HashSet;
-import java.util.Set;
-
-public final class ReaderRegistryBuilderProvider extends ProviderTrait<ModifiableReaderRegistryBuilder> {
-
-    @Inject(optional = true)
-    private Set<ReaderFactory> readerFactories = new HashSet<>();
-
-    @Override
-    protected CompositeReaderRegistryBuilder create() {
-        final CompositeReaderRegistryBuilder builder = new CompositeReaderRegistryBuilder();
-        readerFactories.stream()
-                .forEach(it -> it.init(builder));
-        return builder;
-    }
-
-}
index 86a5ff8..8f6bb0e 100644 (file)
@@ -21,6 +21,7 @@ import io.fd.honeycomb.infra.distro.ProviderTrait;
 import io.fd.honeycomb.translate.impl.read.registry.CompositeReaderRegistryBuilder;
 import io.fd.honeycomb.translate.read.ReaderFactory;
 import io.fd.honeycomb.translate.read.registry.ReaderRegistry;
+import io.fd.honeycomb.translate.util.YangDAG;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -31,7 +32,7 @@ public final class ReaderRegistryProvider extends ProviderTrait<ReaderRegistry>
 
     @Override
     protected ReaderRegistry create() {
-        final CompositeReaderRegistryBuilder builder = new CompositeReaderRegistryBuilder();
+        final CompositeReaderRegistryBuilder builder = new CompositeReaderRegistryBuilder(new YangDAG());
         readerFactories.stream()
             .forEach(it -> it.init(builder));
         return builder.build();
index 9163e98..f8290f1 100644 (file)
@@ -16,6 +16,8 @@
 
 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;
@@ -26,14 +28,13 @@ import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder;
 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;
@@ -42,8 +43,6 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import static com.google.common.base.Preconditions.checkArgument;
-
 @NotThreadSafe
 public final class CompositeReaderRegistryBuilder
         extends AbstractSubtreeManagerRegistryBuilderBuilder<Reader<? extends DataObject, ? extends Builder<?>>, ReaderRegistry>
@@ -51,6 +50,10 @@ public final class CompositeReaderRegistryBuilder
 
     private static final Logger LOG = LoggerFactory.getLogger(CompositeReaderRegistryBuilder.class);
 
+    public CompositeReaderRegistryBuilder(@Nonnull final YangDAG yangDAG) {
+        super(yangDAG);
+    }
+
     @Override
     protected Reader<? extends DataObject, ? extends Builder<?>> getSubtreeHandler(@Nonnull final Set<InstanceIdentifier<?>> handledChildren,
                                                                                    @Nonnull final Reader<? extends DataObject, ? extends Builder<?>> reader) {
index 936aa3c..0c6d0a1 100644 (file)
@@ -18,11 +18,12 @@ package io.fd.honeycomb.translate.impl.write.registry;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableMap;
-import io.fd.honeycomb.translate.write.registry.WriterRegistryBuilder;
 import io.fd.honeycomb.translate.util.AbstractSubtreeManagerRegistryBuilderBuilder;
+import io.fd.honeycomb.translate.util.YangDAG;
 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;
@@ -42,6 +43,10 @@ public final class FlatWriterRegistryBuilder
 
     private static final Logger LOG = LoggerFactory.getLogger(FlatWriterRegistryBuilder.class);
 
+    public FlatWriterRegistryBuilder(@Nonnull final YangDAG yangDAG) {
+        super(yangDAG);
+    }
+
     @Override
     protected Writer<? extends DataObject> getSubtreeHandler(final @Nonnull Set<InstanceIdentifier<?>> handledChildren,
                                                              final @Nonnull Writer<? extends DataObject> writer) {
index 0c7c71e..1858f22 100644 (file)
@@ -26,6 +26,7 @@ import com.google.common.collect.Lists;
 import io.fd.honeycomb.translate.read.Reader;
 import io.fd.honeycomb.translate.read.registry.ReaderRegistry;
 import io.fd.honeycomb.translate.util.DataObjects;
+import io.fd.honeycomb.translate.util.YangDAG;
 import java.util.List;
 import java.util.Map;
 import org.junit.Test;
@@ -68,12 +69,12 @@ public class CompositeReaderRegistryBuilderTest {
 
     @Test(expected = IllegalArgumentException.class)
     public void testPreventStructuralReaderForList() {
-        new CompositeReaderRegistryBuilder().addStructuralReader(InstanceIdentifier.create(DataObjects.DataObjectK.class), DataObjects.DataObjectKBuilder.class);
+        new CompositeReaderRegistryBuilder(new YangDAG()).addStructuralReader(InstanceIdentifier.create(DataObjects.DataObjectK.class), DataObjects.DataObjectKBuilder.class);
     }
 
     @Test
     public void testCompositeStructure() throws Exception {
-        final CompositeReaderRegistryBuilder compositeReaderRegistryBuilder = new CompositeReaderRegistryBuilder();
+        final CompositeReaderRegistryBuilder compositeReaderRegistryBuilder = new CompositeReaderRegistryBuilder(new YangDAG());
         /*
             Composite reader structure ordered left from right
 
index 3a67672..feaba72 100644 (file)
@@ -32,6 +32,7 @@ import com.google.common.collect.Lists;
 import com.google.common.collect.Multimaps;
 import com.google.common.collect.Sets;
 import io.fd.honeycomb.translate.util.DataObjects;
+import io.fd.honeycomb.translate.util.YangDAG;
 import io.fd.honeycomb.translate.write.DataObjectUpdate;
 import io.fd.honeycomb.translate.write.WriteContext;
 import io.fd.honeycomb.translate.write.Writer;
@@ -45,10 +46,9 @@ import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
 public class FlatWriterRegistryBuilderTest {
-
     @Test
     public void testRelationsBefore() throws Exception {
-        final FlatWriterRegistryBuilder flatWriterRegistryBuilder = new FlatWriterRegistryBuilder();
+        final FlatWriterRegistryBuilder flatWriterRegistryBuilder = new FlatWriterRegistryBuilder(new YangDAG());
         /*
             1   ->  2   ->  3
                         ->  4
@@ -70,7 +70,7 @@ public class FlatWriterRegistryBuilderTest {
 
     @Test
     public void testBuild() throws Exception {
-        final FlatWriterRegistryBuilder flatWriterRegistryBuilder = new FlatWriterRegistryBuilder();
+        final FlatWriterRegistryBuilder flatWriterRegistryBuilder = new FlatWriterRegistryBuilder(new YangDAG());
         final Writer<? extends DataObject> writer = mockWriter(DataObjects.DataObject3.class);
         flatWriterRegistryBuilder.add(writer);
         final WriterRegistry build = flatWriterRegistryBuilder.build();
@@ -94,7 +94,7 @@ public class FlatWriterRegistryBuilderTest {
 
     @Test(expected = IllegalArgumentException.class)
     public void testBuildUnknownWriter() throws Exception {
-        final FlatWriterRegistryBuilder flatWriterRegistryBuilder = new FlatWriterRegistryBuilder();
+        final FlatWriterRegistryBuilder flatWriterRegistryBuilder = new FlatWriterRegistryBuilder(new YangDAG());
         final Writer<? extends DataObject> writer = mockWriter(DataObjects.DataObject3.class);
         flatWriterRegistryBuilder.add(writer);
         final WriterRegistry build = flatWriterRegistryBuilder.build();
@@ -109,7 +109,7 @@ public class FlatWriterRegistryBuilderTest {
 
     @Test
     public void testRelationsAfter() throws Exception {
-        final FlatWriterRegistryBuilder flatWriterRegistryBuilder = new FlatWriterRegistryBuilder();
+        final FlatWriterRegistryBuilder flatWriterRegistryBuilder = new FlatWriterRegistryBuilder(new YangDAG());
         /*
             1   ->  2   ->  3
                         ->  4
@@ -131,7 +131,7 @@ public class FlatWriterRegistryBuilderTest {
 
     @Test(expected = IllegalArgumentException.class)
     public void testRelationsLoop() throws Exception {
-        final FlatWriterRegistryBuilder flatWriterRegistryBuilder = new FlatWriterRegistryBuilder();
+        final FlatWriterRegistryBuilder flatWriterRegistryBuilder = new FlatWriterRegistryBuilder(new YangDAG());
         /*
             1   ->  2   ->  1
          */
@@ -142,14 +142,14 @@ public class FlatWriterRegistryBuilderTest {
 
     @Test(expected = IllegalArgumentException.class)
     public void testAddWriterTwice() throws Exception {
-        final FlatWriterRegistryBuilder flatWriterRegistryBuilder = new FlatWriterRegistryBuilder();
+        final FlatWriterRegistryBuilder flatWriterRegistryBuilder = new FlatWriterRegistryBuilder(new YangDAG());
         flatWriterRegistryBuilder.add(mockWriter(DataObjects.DataObject1.class));
         flatWriterRegistryBuilder.add(mockWriter(DataObjects.DataObject1.class));
     }
 
     @Test
     public void testAddSubtreeWriter() throws Exception {
-        final FlatWriterRegistryBuilder flatWriterRegistryBuilder = new FlatWriterRegistryBuilder();
+        final FlatWriterRegistryBuilder flatWriterRegistryBuilder = new FlatWriterRegistryBuilder(new YangDAG());
         flatWriterRegistryBuilder.subtreeAdd(
                 Sets.newHashSet(DataObjects.DataObject4.DataObject41.IID,
                                 DataObjects.DataObject4.DataObject41.IID),
index 6a19ed2..fe2f117 100644 (file)
@@ -18,7 +18,6 @@ package io.fd.honeycomb.translate.util;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Sets;
 import io.fd.honeycomb.translate.ModifiableSubtreeManagerRegistryBuilder;
 import io.fd.honeycomb.translate.SubtreeManager;
 import io.fd.honeycomb.translate.SubtreeManagerRegistryBuilder;
@@ -27,17 +26,18 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
 import javax.annotation.Nonnull;
-import org.jgrapht.experimental.dag.DirectedAcyclicGraph;
 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>, AutoCloseable {
+        implements ModifiableSubtreeManagerRegistryBuilder<S>, SubtreeManagerRegistryBuilder<R> {
 
-    // Using directed acyclic graph to represent the ordering relationships between writers
-    private final DirectedAcyclicGraph<InstanceIdentifier<?>, Order>
-            handlersRelations = new DirectedAcyclicGraph<>((sourceVertex, targetVertex) -> new Order());
     private final Map<InstanceIdentifier<?>, S> handlersMap = new HashMap<>();
+    private final YangDAG dag;
+
+    protected AbstractSubtreeManagerRegistryBuilderBuilder(@Nonnull final YangDAG yangDAG) {
+        this.dag = Preconditions.checkNotNull(yangDAG, "yangDAG should not be null");
+    }
 
     /**
      * Add handler without any special relationship to any other type.
@@ -49,7 +49,7 @@ public abstract class AbstractSubtreeManagerRegistryBuilderBuilder<S extends Sub
         // not be matched to writers in registry
         final InstanceIdentifier<?> targetType = RWUtils.makeIidWildcarded(handler.getManagedDataObjectType());
         checkWriterNotPresentYet(targetType);
-        handlersRelations.addVertex(targetType);
+        dag.addVertex(targetType);
         handlersMap.put(targetType, handler);
         return this;
     }
@@ -78,9 +78,9 @@ public abstract class AbstractSubtreeManagerRegistryBuilderBuilder<S extends Sub
         final InstanceIdentifier<?> targetType = RWUtils.makeIidWildcarded(handler.getManagedDataObjectType());
         final InstanceIdentifier<?> wildcardedRelatedType = RWUtils.makeIidWildcarded(relatedType);
         checkWriterNotPresentYet(targetType);
-        handlersRelations.addVertex(targetType);
-        handlersRelations.addVertex(wildcardedRelatedType);
-        addEdge(targetType, wildcardedRelatedType);
+        dag.addVertex(targetType);
+        dag.addVertex(wildcardedRelatedType);
+        dag.addEdge(targetType, wildcardedRelatedType);
         handlersMap.put(targetType, handler);
         return this;
     }
@@ -90,13 +90,13 @@ public abstract class AbstractSubtreeManagerRegistryBuilderBuilder<S extends Sub
                                                                         @Nonnull final Collection<InstanceIdentifier<?>> relatedTypes) {
         final InstanceIdentifier<?> targetType = RWUtils.makeIidWildcarded(handler.getManagedDataObjectType());
         checkWriterNotPresentYet(targetType);
-        handlersRelations.addVertex(targetType);
+        dag.addVertex(targetType);
         relatedTypes.stream()
                 .map(RWUtils::makeIidWildcarded)
-                .forEach(handlersRelations::addVertex);
+                .forEach(dag::addVertex);
         relatedTypes.stream()
                 .map(RWUtils::makeIidWildcarded)
-                .forEach(type -> addEdge(targetType, type));
+                .forEach(type -> dag.addEdge(targetType, type));
         handlersMap.put(targetType, handler);
         return this;
     }
@@ -129,10 +129,10 @@ public abstract class AbstractSubtreeManagerRegistryBuilderBuilder<S extends Sub
         final InstanceIdentifier<?> targetType = RWUtils.makeIidWildcarded(handler.getManagedDataObjectType());
         final InstanceIdentifier<?> wildcardedRelatedType = RWUtils.makeIidWildcarded(relatedType);
         checkWriterNotPresentYet(targetType);
-        handlersRelations.addVertex(targetType);
-        handlersRelations.addVertex(wildcardedRelatedType);
+        dag.addVertex(targetType);
+        dag.addVertex(wildcardedRelatedType);
         // set edge to indicate before relationship, just reversed
-        addEdge(wildcardedRelatedType, targetType);
+        dag.addEdge(wildcardedRelatedType, targetType);
         handlersMap.put(targetType, handler);
         return this;
     }
@@ -142,14 +142,14 @@ public abstract class AbstractSubtreeManagerRegistryBuilderBuilder<S extends Sub
                                                                        @Nonnull final Collection<InstanceIdentifier<?>> relatedTypes) {
         final InstanceIdentifier<?> targetType = RWUtils.makeIidWildcarded(handler.getManagedDataObjectType());
         checkWriterNotPresentYet(targetType);
-        handlersRelations.addVertex(targetType);
+        dag.addVertex(targetType);
         relatedTypes.stream()
                 .map(RWUtils::makeIidWildcarded)
-                .forEach(handlersRelations::addVertex);
+                .forEach(dag::addVertex);
         // set edge to indicate before relationship, just reversed
         relatedTypes.stream()
                 .map(RWUtils::makeIidWildcarded)
-                .forEach(type -> addEdge(type, targetType));
+                .forEach(type -> dag.addEdge(type, targetType));
         handlersMap.put(targetType, handler);
         return this;
     }
@@ -170,22 +170,10 @@ public abstract class AbstractSubtreeManagerRegistryBuilderBuilder<S extends Sub
         return addAfter(getSubtreeHandler(handledChildren, handler), relatedTypes);
     }
 
-
-    private void addEdge(final InstanceIdentifier<?> targetType,
-                         final InstanceIdentifier<?> relatedType) {
-        try {
-            handlersRelations.addDagEdge(targetType, relatedType);
-        } catch (DirectedAcyclicGraph.CycleFoundException e) {
-            throw new IllegalArgumentException(String.format(
-                    "Unable to add writer with relation: %s -> %s. Loop detected", targetType, relatedType), e);
-        }
-    }
-
     protected ImmutableMap<InstanceIdentifier<?>, S> getMappedHandlers() {
         final ImmutableMap.Builder<InstanceIdentifier<?>, S> builder = ImmutableMap.builder();
         // Iterate writer types according to their relationships from graph
-        handlersRelations.iterator()
-                .forEachRemaining(handlerType -> {
+        dag.iterator().forEachRemaining(handlerType -> {
                     // There might be types stored just for relationship sake, no real writer, ignoring those
                     if (handlersMap.containsKey(handlerType)) {
                         builder.put(handlerType, handlersMap.get(handlerType));
@@ -199,15 +187,4 @@ public abstract class AbstractSubtreeManagerRegistryBuilderBuilder<S extends Sub
 
         return builder.build();
     }
-
-    @Override
-    public void close() throws Exception {
-        handlersMap.clear();
-        // Wrap sets into another set to avoid concurrent modification ex in graph
-        handlersRelations.removeAllEdges(Sets.newHashSet(handlersRelations.edgeSet()));
-        handlersRelations.removeAllVertices(Sets.newHashSet(handlersRelations.vertexSet()));
-    }
-
-    // Represents edges in graph
-    private class Order {}
 }
diff --git a/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/YangDAG.java b/infra/translate-utils/src/main/java/io/fd/honeycomb/translate/util/YangDAG.java
new file mode 100644 (file)
index 0000000..2269adb
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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.util;
+
+import java.util.Iterator;
+import org.jgrapht.experimental.dag.DirectedAcyclicGraph;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Directed acyclic graph representing ordering relationships between schema nodes represented as wildcarded
+ * InstanceIdentifiers. Maintains topological order of vertices. Feature is used by translation layer if more nodes are
+ * affected in single read/write transaction.
+ */
+public final class YangDAG {
+
+    private final DirectedAcyclicGraph<InstanceIdentifier<?>, Edge>
+        dag = new DirectedAcyclicGraph<>((sourceVertex, targetVertex) -> new Edge());
+
+    /**
+     * Adds the vertex if it wasn't already in the graph.
+     *
+     * @param vertex vertex to be added
+     */
+    public void addVertex(final InstanceIdentifier<?> vertex) {
+        dag.addVertex(vertex);
+    }
+
+    /**
+     * Adds edge between source and target vertices.
+     *
+     * @param source source vertex of the edge
+     * @param target target vertex of the edge
+     * @throws IllegalArgumentException if the edge would induce a cycle in the graph
+     */
+    public void addEdge(final InstanceIdentifier<?> source, final InstanceIdentifier<?> target) {
+        try {
+            dag.addDagEdge(source, target);
+        } catch (DirectedAcyclicGraph.CycleFoundException e) {
+            throw new IllegalArgumentException(String.format(
+                "Unable to add writer with relation: %s -> %s. Loop detected", source, target), e);
+        }
+    }
+
+    /**
+     * Traverses schema nodes in topological order.
+     *
+     * @return an iterator that will traverse the graph in topological order.
+     */
+    public Iterator<InstanceIdentifier<?>> iterator() {
+        return dag.iterator();
+    }
+
+    private static final class Edge {
+    }
+}
diff --git a/infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/YangDAGTest.java b/infra/translate-utils/src/test/java/io/fd/honeycomb/translate/util/YangDAGTest.java
new file mode 100644 (file)
index 0000000..1c8fb54
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Iterator;
+import org.jgrapht.experimental.dag.DirectedAcyclicGraph;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class YangDAGTest {
+
+    private static final InstanceIdentifier<DataObjects.DataObject1> VERTEX_A = DataObjects.DataObject1.IID;
+    private static final InstanceIdentifier<DataObjects.DataObject2> VERTEX_B = DataObjects.DataObject2.IID;
+
+    private YangDAG dag;
+
+    @Before
+    public void setUp() {
+        dag = new YangDAG();
+    }
+    @Test
+    public void testAddVertex() {
+        dag.addVertex(VERTEX_A);
+        final Iterator<InstanceIdentifier<?>> it = dag.iterator();
+        assertEquals(VERTEX_A, it.next());
+        assertFalse(it.hasNext());
+    }
+
+    @Test
+    public void testAddEdge() {
+        dag.addVertex(VERTEX_A);
+        dag.addVertex(VERTEX_B);
+        dag.addEdge(VERTEX_A, VERTEX_B);
+        final Iterator<InstanceIdentifier<?>> it = dag.iterator();
+        assertEquals(VERTEX_A, it.next());
+        assertEquals(VERTEX_B, it.next());
+        assertFalse(it.hasNext());
+    }
+
+    @Test
+    public void testAddCycleFails() {
+        dag.addVertex(VERTEX_A);
+        dag.addVertex(VERTEX_B);
+        dag.addEdge(VERTEX_A, VERTEX_B);
+        try {
+            dag.addEdge(VERTEX_B, VERTEX_A);
+        } catch (IllegalArgumentException e) {
+            assertTrue(e.getCause() instanceof DirectedAcyclicGraph.CycleFoundException);
+        }
+    }
+}
\ No newline at end of file