HONEYCOMB-122: Reader registry integration tests
authorMaros Marsalek <[email protected]>
Thu, 14 Jul 2016 08:41:49 +0000 (10:41 +0200)
committerMaros Marsalek <[email protected]>
Mon, 25 Jul 2016 08:34:16 +0000 (10:34 +0200)
Add IT test for read infrastructure + some additional unit tests

+ Make Read/Write Factory autoCloseable

Change-Id: I6eab8e6df2c2132af01cea0a9c4b9bece7dc9b74
Signed-off-by: Maros Marsalek <[email protected]>
33 files changed:
v3po/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/ContextReaderModule.java
v3po/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/NetconfMonitoringReaderModule.java
v3po/it/it-test/pom.xml
v3po/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/AbstractInfraTest.java [new file with mode: 0644]
v3po/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombReadInfraTest.java [new file with mode: 0644]
v3po/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombSubtreeReadInfraTest.java [new file with mode: 0644]
v3po/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombWriteInfraTest.java
v3po/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/Ids.java [new file with mode: 0644]
v3po/it/test-model/src/main/yang/hc-test.yang
v3po/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/read/ReaderFactory.java
v3po/translate-api/src/main/java/io/fd/honeycomb/v3po/translate/write/WriterFactory.java
v3po/translate-impl/src/main/java/io/fd/honeycomb/v3po/translate/impl/read/GenericListReader.java
v3po/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/RWUtils.java
v3po/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/ReflectionUtils.java
v3po/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/ReflexiveListReaderCustomizer.java [new file with mode: 0644]
v3po/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/ReflexiveReader.java
v3po/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/ReflexiveReaderCustomizer.java
v3po/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/registry/CompositeReader.java
v3po/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/registry/CompositeReaderRegistry.java
v3po/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/registry/SubtreeReader.java
v3po/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/DataObjects.java [new file with mode: 0644]
v3po/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/read/registry/CompositeReaderRegistryBuilderTest.java [new file with mode: 0644]
v3po/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/read/registry/SubtreeReaderTest.java [new file with mode: 0644]
v3po/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/read/registry/TypeHierarchyTest.java
v3po/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/write/registry/FlatWriterRegistryBuilderTest.java
v3po/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/write/registry/FlatWriterRegistryTest.java
v3po/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/write/registry/SubtreeWriterTest.java
v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesHoneycombWriterModule.java
v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesStateHoneycombReaderModule.java
v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppClassifierHoneycombWriterModule.java
v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppClassifierStateHoneycombReaderModule.java
v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppHoneycombWriterModule.java
v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/VppStateHoneycombReaderModule.java

index c15fe52..2b625d7 100644 (file)
@@ -44,10 +44,5 @@ public class ContextReaderModule extends org.opendaylight.yang.gen.v1.urn.openda
                     contextBindingBrokerDependency,
                     LogicalDatastoreType.OPERATIONAL, ContextsBuilder.class));
         }
-
-        @Override
-        public void close() throws Exception {
-            // TODO no unregister
-        }
     }
 }
index 4557518..8502fcb 100644 (file)
@@ -42,10 +42,5 @@ public class NetconfMonitoringReaderModule extends org.opendaylight.yang.gen.v1.
                     netconfMonitoringBindingBrokerDependency,
                     LogicalDatastoreType.OPERATIONAL, NetconfStateBuilder.class));
         }
-
-        @Override
-        public void close() throws Exception {
-            // TODO no unregister
-        }
     }
 }
index 04e70e9..74bb545 100644 (file)
             <artifactId>data-impl</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>io.fd.honeycomb.v3po</groupId>
+            <artifactId>translate-impl</artifactId>
+            <version>${project.version}</version>
+        </dependency>
         <dependency>
             <groupId>org.skinny-framework</groupId>
             <artifactId>skinny-logback</artifactId>
diff --git a/v3po/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/AbstractInfraTest.java b/v3po/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/AbstractInfraTest.java
new file mode 100644 (file)
index 0000000..47644cc
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.data.impl;
+
+import static org.mockito.Mockito.when;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+import com.google.common.util.concurrent.Futures;
+import java.util.Collections;
+import java.util.Map;
+import javassist.ClassPool;
+import org.junit.Before;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.$YangModuleInfoImpl;
+import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.DataObjectSerializerGenerator;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
+import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
+import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+/**
+ * Base IT test infrastructure.
+ */
+abstract class AbstractInfraTest {
+
+    protected BindingNormalizedNodeSerializer serializer;
+    protected SchemaContext schemaContext;
+
+    @Mock
+    protected org.opendaylight.controller.md.sal.binding.api.DataBroker contextBroker;
+    @Mock
+    private org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction ctxTx;
+
+    static BindingToNormalizedNodeCodec getSerializer(final ModuleInfoBackedContext moduleInfoBackedContext,
+                                                      final SchemaContext schemaContext) {
+        final DataObjectSerializerGenerator serializerGenerator = new StreamWriterGenerator(JavassistUtils.forClassPool(
+                ClassPool.getDefault()));
+        final BindingNormalizedNodeCodecRegistry codecRegistry = new BindingNormalizedNodeCodecRegistry(serializerGenerator);
+        final BindingRuntimeContext ctx =
+                BindingRuntimeContext.create(moduleInfoBackedContext, schemaContext);
+        codecRegistry.onBindingRuntimeContextUpdated(ctx);
+        return new BindingToNormalizedNodeCodec(moduleInfoBackedContext, codecRegistry);
+    }
+
+    static ModuleInfoBackedContext getSchemaContext() {
+        final ModuleInfoBackedContext moduleInfoBackedContext = ModuleInfoBackedContext.create();
+        moduleInfoBackedContext.addModuleInfos(Collections.singleton($YangModuleInfoImpl.getInstance()));
+        return moduleInfoBackedContext;
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        when(contextBroker.newReadWriteTransaction()).thenReturn(ctxTx);
+        when(ctxTx.submit()).thenReturn(Futures.immediateCheckedFuture(null));
+
+        initSerializer();
+        postSetup();
+    }
+
+    abstract void postSetup();
+
+    private void initSerializer() {
+        final ModuleInfoBackedContext moduleInfoBackedContext = getSchemaContext();
+        schemaContext = moduleInfoBackedContext.tryToCreateSchemaContext().get();
+        serializer = getSerializer(moduleInfoBackedContext, schemaContext);
+    }
+
+    protected Multimap<InstanceIdentifier<? extends DataObject>, ? extends DataObject> toBinding(
+            final NormalizedNode<?, ?> read) {
+        Multimap<InstanceIdentifier<? extends DataObject>, DataObject> baNodes = HashMultimap.create();
+
+        for (DataContainerChild<?, ?> o : ((DataContainerNode<?>) read).getValue()) {
+            final YangInstanceIdentifier yid = YangInstanceIdentifier.of(o.getNodeType());
+            final Map.Entry<InstanceIdentifier<?>, DataObject> baEntry = serializer.fromNormalizedNode(yid, o);
+            baNodes.put(baEntry.getKey(), baEntry.getValue());
+        }
+        return baNodes;
+    }
+}
diff --git a/v3po/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombReadInfraTest.java b/v3po/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombReadInfraTest.java
new file mode 100644 (file)
index 0000000..b1f3a19
--- /dev/null
@@ -0,0 +1,460 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.data.impl;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyListOf;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
+import com.google.common.util.concurrent.CheckedFuture;
+import io.fd.honeycomb.v3po.translate.impl.read.GenericListReader;
+import io.fd.honeycomb.v3po.translate.read.ListReader;
+import io.fd.honeycomb.v3po.translate.read.ReadContext;
+import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
+import io.fd.honeycomb.v3po.translate.read.Reader;
+import io.fd.honeycomb.v3po.translate.read.registry.ReaderRegistry;
+import io.fd.honeycomb.v3po.translate.util.RWUtils;
+import io.fd.honeycomb.v3po.translate.util.read.ReflexiveListReaderCustomizer;
+import io.fd.honeycomb.v3po.translate.util.read.ReflexiveReader;
+import io.fd.honeycomb.v3po.translate.util.read.registry.CompositeReaderRegistryBuilder;
+import java.lang.reflect.InvocationTargetException;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.junit.Test;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.exceptions.misusing.MockitoConfigurationException;
+import org.mockito.invocation.InvocationOnMock;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ComplexAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ComplexAugmentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleAugmentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleContainer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleContainerBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainerBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainerKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.container.in.list.NestedList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.container.in.list.NestedListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.container.in.list.NestedListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.simple.container.ComplexAugmentContainer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.simple.container.ComplexAugmentContainerBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public class HoneycombReadInfraTest extends AbstractInfraTest {
+
+    @Mock
+    private ReadContext ctx;
+    private ReaderRegistry registry;
+
+    // 1
+    private Reader<SimpleContainer, SimpleContainerBuilder> simpleContainerReader =
+            mockReader(Ids.SIMPLE_CONTAINER_ID, this::readSimpleContainer, SimpleContainerBuilder.class);
+    // 1.1
+    private Reader<SimpleAugment, SimpleAugmentBuilder> simpleAugmentReader =
+            mockReader(Ids.SIMPLE_AUGMENT_ID, this::readSimpleAugment, SimpleAugmentBuilder.class);
+    // 1.2
+    // Noop reader(no real attributes)
+    private Reader<ComplexAugment, ComplexAugmentBuilder> complexAugmentReader =
+            mockReader(Ids.COMPLEX_AUGMENT_ID, HoneycombReadInfraTest::noopRead, ComplexAugmentBuilder.class);
+    // 1.2.1
+    private Reader<ComplexAugmentContainer, ComplexAugmentContainerBuilder> complexAugmentContainerReader =
+            mockReader(Ids.COMPLEX_AUGMENT_CONTAINER_ID, this::readComplexAugmentContainer, ComplexAugmentContainerBuilder.class);
+    // 2
+    // Noop reader(no real attributes)
+    private Reader<ContainerWithList, ContainerWithListBuilder> containerWithListReader =
+            mockReader(Ids.CONTAINER_WITH_LIST_ID, HoneycombReadInfraTest::noopRead, ContainerWithListBuilder.class);
+    // 2.1
+    private ListReader<ListInContainer, ListInContainerKey, ListInContainerBuilder> listInContainerReader =
+            mockListReader(Ids.LIST_IN_CONTAINER_ID, this::readListInContainer, this::getListInContainerIds,
+                    ListInContainerBuilder.class);
+    // 2.1.1
+    private Reader<ContainerInList, ContainerInListBuilder> containerInListReader =
+            mockReader(Ids.CONTAINER_IN_LIST_ID, this::readContainerInList, ContainerInListBuilder.class);
+    // 2.1.1.1
+    private ListReader<NestedList, NestedListKey, NestedListBuilder> nestedListReader =
+            mockListReader(Ids.NESTED_LIST_ID, this::readNestedList, this::getNestedListIds,
+                    NestedListBuilder.class);
+
+    @Override
+    void postSetup() {
+        initReaderRegistry();
+    }
+
+    private void initReaderRegistry() {
+        registry = new CompositeReaderRegistryBuilder()
+                .add(containerWithListReader) // 2
+                .addBefore(simpleContainerReader, Ids.CONTAINER_WITH_LIST_ID) // 1
+                .add(simpleAugmentReader) // 1.1
+                .addAfter(complexAugmentReader, Ids.SIMPLE_AUGMENT_ID) // 1.2
+                .add(complexAugmentContainerReader) // 1.2.1
+                .add(listInContainerReader) // 2.1
+                .add(containerInListReader) // 2.1.1
+                .addBefore(nestedListReader, Ids.SIMPLE_AUGMENT_ID) // 2.1.1.1 - Before relationship should be ignored
+        .build();
+    }
+
+    private Reader<?, ?>[] getOrderedReaders() {
+        return new Reader<?, ?>[]{simpleContainerReader, // 1
+                simpleAugmentReader, // 1.1
+                complexAugmentReader, // 1.2
+                complexAugmentContainerReader, // 1.2.1
+                containerWithListReader, // 2
+                listInContainerReader, // 2.1
+                containerInListReader, // 2.1.1
+                nestedListReader}; // 2.1.1.1
+    }
+
+    @Test
+    public void testReadAll() throws Exception {
+        final ReadableDataTreeDelegator readableDataTreeDelegator =
+                new ReadableDataTreeDelegator(serializer, schemaContext, registry, contextBroker);
+        final CheckedFuture<Optional<NormalizedNode<?, ?>>, org.opendaylight.controller.md.sal.common.api.data.ReadFailedException>
+                read = readableDataTreeDelegator.read(YangInstanceIdentifier.EMPTY);
+
+        final Multimap<InstanceIdentifier<? extends DataObject>, ? extends DataObject> readAll =
+                toBinding(read.checkedGet().get());
+        assertThat(readAll.size(), is(2));
+        assertTrue(readAll.containsKey(Ids.CONTAINER_WITH_LIST_ID));
+        assertEquals(readContainerWithList(), readAll.get(Ids.CONTAINER_WITH_LIST_ID).stream().findFirst().get());
+        assertTrue(readAll.containsKey(Ids.SIMPLE_CONTAINER_ID));
+        assertEquals(readSimpleContainer(), readAll.get(Ids.SIMPLE_CONTAINER_ID).stream().findFirst().get());
+
+        final Reader<?, ?>[] ordered = getOrderedReaders();
+        final InOrder inOrder = inOrder(ordered);
+
+        final List<ListInContainerKey> listInContainerKeys = getListInContainerIds(Ids.LIST_IN_CONTAINER_ID, ctx);
+
+        verifyRootReader(inOrder, simpleContainerReader, Ids.SIMPLE_CONTAINER_ID, SimpleContainerBuilder.class);
+        verifyLeafChildReader(inOrder, simpleAugmentReader, Ids.SIMPLE_AUGMENT_ID);
+        verifyCompositeChildReader(inOrder, complexAugmentReader, ComplexAugmentBuilder.class, Ids.COMPLEX_AUGMENT_ID);
+        verifyLeafChildReader(inOrder, complexAugmentContainerReader, Ids.COMPLEX_AUGMENT_CONTAINER_ID);
+        verifyRootReader(inOrder, containerWithListReader, Ids.CONTAINER_WITH_LIST_ID, ContainerWithListBuilder.class);
+        verifyCompositeListReader(inOrder, listInContainerReader, Ids.LIST_IN_CONTAINER_ID,
+                listInContainerKeys, ListInContainerBuilder.class);
+
+        for (ListInContainerKey k : listInContainerKeys) {
+            final InstanceIdentifier<ContainerInList> id =
+                    Ids.CONTAINER_WITH_LIST_ID.child(ListInContainer.class, k).child(ContainerInList.class);
+            verifyCompositeChildReader(inOrder, containerInListReader, ContainerInListBuilder.class, id);
+            final InstanceIdentifier<NestedList> nestedId = id.child(NestedList.class);
+            verifyLeafListReader(inOrder, nestedListReader, nestedId);
+        }
+
+        for (Reader<?, ?> reader : ordered) {
+            verifyNoMoreReadInteractions(reader);
+        }
+    }
+
+    private <D extends DataObject, B extends Builder<D>> void verifyNoMoreReadInteractions(final Reader<D, B> reader) {
+        verify(reader, atLeastOnce()).getManagedDataObjectType();
+        verifyNoMoreInteractions(reader);
+    }
+
+    private <D extends DataObject, B extends Builder<D>> void verifyCompositeChildReader(final InOrder inOrder,
+                                                                                         final Reader<D, B> reader,
+                                                                                         final Class<B> builderCls,
+                                                                                         final InstanceIdentifier<D> id)
+            throws ReadFailedException {
+        verifyRootReader(inOrder, reader, id, builderCls);
+        verify(reader, atLeastOnce()).merge(any(Builder.class), any(id.getTargetType()));
+    }
+
+    private <D extends DataObject & Identifiable<K>, K extends Identifier<D>, B extends Builder<D>> void verifyCompositeListReader(
+            final InOrder inOrder,
+            final ListReader<D, K, B> reader,
+            final InstanceIdentifier<D> id,
+            final List<K> keys,
+            final Class<B> builderCls)
+            throws ReadFailedException {
+
+        // Id has to be wildcarded, since it was created using InstanceIdentifier.child() method
+        inOrder.verify(reader).getAllIds(eq(RWUtils.makeIidLastWildcarded(id)), any(ReadContext.class));
+        keys.stream()
+                .map(k -> RWUtils.replaceLastInId(id, RWUtils.getCurrentIdItem(id, k)))
+                .forEach(keyedId -> {
+                    try {
+                        verify(reader).getBuilder(keyedId);
+                        verify(reader).readCurrentAttributes(eq(keyedId), any(builderCls), any(ReadContext.class));
+                    } catch (ReadFailedException e) { throw new RuntimeException(e); }
+                });
+        verify(reader, atLeastOnce()).merge(any(Builder.class), anyListOf(id.getTargetType()));
+    }
+
+    private <D extends DataObject & Identifiable<K>, K extends Identifier<D>, B extends Builder<D>> void verifyLeafListReader(
+            final InOrder inOrder,
+            final ListReader<D, K, B> reader,
+            final InstanceIdentifier<D> id)
+            throws ReadFailedException {
+
+        // Id has to be wildcarded, since it was created using InstanceIdentifier.child() method
+        inOrder.verify(reader).readList(eq(RWUtils.makeIidLastWildcarded(id)), any(ReadContext.class));
+        verify(reader, atLeastOnce()).merge(any(Builder.class), anyListOf(id.getTargetType()));
+    }
+
+    private <D extends DataObject, B extends Builder<D>> void verifyRootReader(final InOrder inOrder,
+                                                                               final Reader<D, B> reader,
+                                                                               final InstanceIdentifier<D> id,
+                                                                               final Class<B> builderCls)
+            throws ReadFailedException {
+        inOrder.verify(reader).readCurrentAttributes(eq(id), any(builderCls), any(ReadContext.class));
+        verify(reader).getBuilder(id);
+    }
+
+
+    private <D extends DataObject, B extends Builder<D>> void verifyLeafChildReader(final InOrder inOrder,
+                                                                                    final Reader<D, B> reader,
+                                                                                    final InstanceIdentifier<D>... id)
+            throws ReadFailedException {
+        for (InstanceIdentifier<D> singleId : id) {
+            inOrder.verify(reader).read(eq(singleId), any(ReadContext.class));
+            verify(reader, atLeastOnce()).merge(any(Builder.class), any(singleId.getTargetType()));
+        }
+    }
+
+    static <D extends DataObject, B extends Builder<D>> Reader<D, B> mockReader(InstanceIdentifier<D> id,
+                                                                                 CurrentAttributesReader<D, B> currentAttributesReader,
+                                                                                 Class<B> builderClass) {
+        final ReflexiveReader<D, B> reflex = new ReflexiveReader<D, B>(id, builderClass) {
+
+            @Override
+            public void readCurrentAttributes(@Nonnull final InstanceIdentifier<D> id,
+                                              @Nonnull final B builder,
+                                              @Nonnull final ReadContext ctx)
+                    throws ReadFailedException {
+                currentAttributesReader.readCurrentAttributes(id, builder, ctx);
+            }
+        };
+
+        // Simple spy on top of this reflexive reader cannot be used, spy also checks protected methods for invocation
+        // but those cannot be verified by mockito
+        final Reader<D, B> mock = mock(Reader.class);
+        try {
+            doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock).read(any(InstanceIdentifier.class), any(ReadContext.class));
+            doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock)
+                    .readCurrentAttributes(any(InstanceIdentifier.class), any(builderClass), any(ReadContext.class));
+            doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock).merge(any(Builder.class), any(id.getTargetType()));
+            doReturn(id).when(mock).getManagedDataObjectType();
+            doReturn(builderClass.newInstance()).when(mock).getBuilder(any(InstanceIdentifier.class));
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+
+        return mock;
+    }
+
+    static <D extends DataObject & Identifiable<K>, K extends Identifier<D>, B extends Builder<D>> ListReader<D, K, B> mockListReader(
+            InstanceIdentifier<D> id,
+            CurrentAttributesReader<D, B> currentAttributesReader,
+            ListKeysReader<D, K> listKeysReader,
+            Class<B> builderClass) {
+
+        ListReader<D, K, B> reflex = new GenericListReader<>(id,
+                new ReflexiveListReaderCustomizer<D, K, B>(id.getTargetType(), builderClass) {
+
+            @Nonnull
+            @Override
+            public List<K> getAllIds(@Nonnull final InstanceIdentifier<D> id, @Nonnull final ReadContext context)
+                    throws ReadFailedException {
+                return listKeysReader.getAllIds(id, context);
+            }
+
+            @Override
+            public void readCurrentAttributes(final InstanceIdentifier<D> id, final B builder,
+                                              final ReadContext context)
+                    throws ReadFailedException {
+                currentAttributesReader.readCurrentAttributes(id, builder, context);
+            }
+        });
+
+        final ListReader<D, K, B> mock = mock(ListReader.class /*, withSettings().verboseLogging()*/);
+        try {
+            // not using eq(id) instead using any(InstanceIdentifier.class) due to InstanceIdentifier.equals weird behavior
+            // with wildcarded instance identifiers for lists
+            doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock).read(any(InstanceIdentifier.class), any(ReadContext.class));
+            doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock)
+                    .readCurrentAttributes(any(InstanceIdentifier.class), any(builderClass), any(ReadContext.class));
+            doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock).merge(any(Builder.class), any(id.getTargetType()));
+            doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock).merge(any(Builder.class), anyListOf(id.getTargetType()));
+            doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock).getAllIds(any(InstanceIdentifier.class), any(ReadContext.class));
+            doAnswer(i -> reflexiveAnswer(reflex, i)).when(mock).readList(any(InstanceIdentifier.class), any(ReadContext.class));
+            doReturn(id).when(mock).getManagedDataObjectType();
+            doReturn(builderClass.newInstance()).when(mock).getBuilder(any(InstanceIdentifier.class));
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+
+        return mock;
+    }
+
+    private static <D extends DataObject, B extends Builder<D>> Object reflexiveAnswer(final Reader<D, B> instance,
+                                                                                final InvocationOnMock i) {
+        try {
+            return i.getMethod().invoke(instance, i.getArguments());
+        } catch (IllegalAccessException | InvocationTargetException e) {
+            throw new MockitoConfigurationException("Unable to invoke stubbed method invocation: " + i + " on " + instance);
+        }
+    }
+
+    @FunctionalInterface
+    interface CurrentAttributesReader<D extends DataObject, B extends Builder<D>> {
+        void readCurrentAttributes(@Nonnull final InstanceIdentifier<D> id,
+                                   @Nonnull final B builder,
+                                   @Nonnull final ReadContext ctx);
+    }
+
+    @FunctionalInterface
+    interface ListKeysReader<D extends DataObject & Identifiable<K>, K extends Identifier<D>> {
+        List<K> getAllIds(@Nonnull final InstanceIdentifier<D> id,
+                          @Nonnull final ReadContext ctx);
+    }
+
+
+    private void readSimpleContainer(final InstanceIdentifier<SimpleContainer> id,
+                                     final SimpleContainerBuilder b,
+                                     final ReadContext readContext) {
+        b.setSimpleContainerName("simple");
+    }
+
+    private SimpleContainer readSimpleContainer() {
+        final SimpleContainerBuilder b = new SimpleContainerBuilder();
+        readSimpleContainer(Ids.SIMPLE_CONTAINER_ID, b, ctx);
+        b.addAugmentation(SimpleAugment.class, readSimpleAugment());
+        b.addAugmentation(ComplexAugment.class,
+                new ComplexAugmentBuilder().setComplexAugmentContainer(readComplexAugmentContainer()).build());
+        return b.build();
+    }
+
+    private void readSimpleAugment(final InstanceIdentifier<SimpleAugment> id,
+                                   final SimpleAugmentBuilder b,
+                                   final ReadContext readContext) {
+        b.setSimpleAugmentLeaf("simple augment");
+    }
+
+    private SimpleAugment readSimpleAugment() {
+        final SimpleAugmentBuilder b = new SimpleAugmentBuilder();
+        readSimpleAugment(Ids.SIMPLE_AUGMENT_ID, b, ctx);
+        return b.build();
+    }
+
+    private void readComplexAugmentContainer(final InstanceIdentifier<ComplexAugmentContainer> id,
+                                             final ComplexAugmentContainerBuilder b,
+                                             final ReadContext readContext) {
+        b.setSomeLeaf("nested container in augment");
+    }
+
+    private ComplexAugmentContainer readComplexAugmentContainer() {
+        final ComplexAugmentContainerBuilder b = new ComplexAugmentContainerBuilder();
+        readComplexAugmentContainer(Ids.COMPLEX_AUGMENT_CONTAINER_ID, b, ctx);
+        return b.build();
+    }
+
+    private ContainerWithList readContainerWithList() {
+        final ContainerWithListBuilder b = new ContainerWithListBuilder();
+        b.setListInContainer(readListInContainer());
+        return b.build();
+    }
+
+    private List<ListInContainerKey> getListInContainerIds(final InstanceIdentifier<ListInContainer> id,
+                                                           final ReadContext readContext) {
+        return Lists.newArrayList(1L, 2L)
+                .stream()
+                .map(ListInContainerKey::new)
+                .collect(Collectors.toList());
+    }
+
+    private List<NestedListKey> getNestedListIds(final InstanceIdentifier<NestedList> id,
+                                                 final ReadContext readContext) {
+        return Lists.newArrayList("one", "two")
+                .stream()
+                .map(NestedListKey::new)
+                .collect(Collectors.toList());
+    }
+
+    private void readListInContainer(final InstanceIdentifier<ListInContainer> id,
+                                     final ListInContainerBuilder b,
+                                     final ReadContext readContext) {
+        final ListInContainerKey key = id.firstKeyOf(ListInContainer.class);
+        b.setId(key.getId());
+        final ContainerInListBuilder cilBuilder = new ContainerInListBuilder();
+        readContainerInList(id.child(ContainerInList.class), cilBuilder, readContext);
+        b.setContainerInList(cilBuilder.build());
+    }
+
+    private void readNestedList(final InstanceIdentifier<NestedList> id,
+                                final NestedListBuilder b,
+                                final ReadContext readContext) {
+        final NestedListKey key = id.firstKeyOf(NestedList.class);
+        b.setNestedId(key.getNestedId());
+        b.setNestedName(key.getNestedId() + "name");
+    }
+
+    private void readContainerInList(final InstanceIdentifier<ContainerInList> id,
+                                     final ContainerInListBuilder b,
+                                     final ReadContext readContext) {
+        b.setName(id.firstKeyOf(ListInContainer.class).getId().toString());
+        b.setNestedList(getNestedListIds(Ids.NESTED_LIST_ID, ctx).stream()
+                .map(key -> id.child(NestedList.class, key))
+                .map(nestedId -> {
+                    final NestedListBuilder nestedB = new NestedListBuilder();
+                    readNestedList(nestedId, nestedB, readContext);
+                    return nestedB.build();
+                })
+                .collect(Collectors.toList()));
+    }
+
+    private List<ListInContainer> readListInContainer() {
+        return getListInContainerIds(Ids.LIST_IN_CONTAINER_ID, ctx).stream()
+                .map(key -> Ids.CONTAINER_WITH_LIST_ID.child(ListInContainer.class, key))
+                .map(id -> {
+                    final ListInContainerBuilder b = new ListInContainerBuilder();
+                    readListInContainer(id, b, ctx);
+                    return b.build();
+                }).collect(Collectors.toList());
+    }
+
+    static <D extends DataObject, B extends Builder<D>> void noopRead(final InstanceIdentifier<D> id, final B b,
+                                                                       final ReadContext readContext) {
+        // NOOP
+    }
+
+}
diff --git a/v3po/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombSubtreeReadInfraTest.java b/v3po/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/HoneycombSubtreeReadInfraTest.java
new file mode 100644 (file)
index 0000000..8faeb84
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.data.impl;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.CheckedFuture;
+import io.fd.honeycomb.v3po.translate.impl.read.GenericListReader;
+import io.fd.honeycomb.v3po.translate.read.ListReader;
+import io.fd.honeycomb.v3po.translate.read.ReadContext;
+import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
+import io.fd.honeycomb.v3po.translate.read.Reader;
+import io.fd.honeycomb.v3po.translate.read.registry.ReaderRegistry;
+import io.fd.honeycomb.v3po.translate.util.read.ReflexiveListReaderCustomizer;
+import io.fd.honeycomb.v3po.translate.util.read.registry.CompositeReaderRegistryBuilder;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainerBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainerKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInListBuilder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public class HoneycombSubtreeReadInfraTest extends AbstractInfraTest {
+
+    @Mock
+    private ReadContext ctx;
+    private ReaderRegistry registry;
+
+    private Reader<ContainerWithList, ContainerWithListBuilder> containerWithListReader =
+            HoneycombReadInfraTest.mockReader(Ids.CONTAINER_WITH_LIST_ID, this::readSubtree, ContainerWithListBuilder.class);
+
+    private ListReader<ListInContainer, ListInContainerKey, ListInContainerBuilder> listInContainerReader =
+            new GenericListReader<>(Ids.LIST_IN_CONTAINER_ID,
+                    new ReflexiveListReaderCustomizer<ListInContainer, ListInContainerKey, ListInContainerBuilder>(Ids.LIST_IN_CONTAINER_ID.getTargetType(), ListInContainerBuilder.class) {
+
+                        @Nonnull
+                        @Override
+                        public List<ListInContainerKey> getAllIds(@Nonnull final InstanceIdentifier<ListInContainer> id,
+                                                                  @Nonnull final ReadContext context)
+                                throws ReadFailedException {
+                            // FIXME this is the only way of extending subtree reader via its list child
+                            // Reflexive list reader has to be used in place of the list(managed by subtree reader perent)
+                            // to enable further children readers. However, it will not work out of the box, because
+                            // reflexive list reader has no way to tell what are the IDs to correctly invoke its children.
+                            // Only way is to override the getAllIds method in reflexive reader and return the same list
+                            // as parent used (this can be done using cache or repeated dump call)
+                            return Lists.newArrayList(new ListInContainerKey(1L), new ListInContainerKey(2L));
+                        }
+
+                        @Override
+                        public void readCurrentAttributes(final InstanceIdentifier<ListInContainer> id,
+                                                          final ListInContainerBuilder builder,
+                                                          final ReadContext context) throws ReadFailedException {
+                            super.readCurrentAttributes(id, builder, context);
+                            builder.setKey(id.firstKeyOf(ListInContainer.class));
+                        }
+                    });
+
+    private Reader<ContainerInList, ContainerInListBuilder> containerInListReader =
+            HoneycombReadInfraTest.mockReader(Ids.CONTAINER_IN_LIST_ID, this::readContainerInList, ContainerInListBuilder.class);
+
+    // TODO Test subtree readers especially composite structure where readers are under subtree reader
+
+    @Override
+    void postSetup() {
+        initReaderRegistry();
+    }
+
+    private void initReaderRegistry() {
+        registry = new CompositeReaderRegistryBuilder()
+                // Subtree reader handling its child list
+                .subtreeAdd(Sets.newHashSet(Ids.LIST_IN_CONTAINER_ID), containerWithListReader)
+                // Reflexive
+                .add(listInContainerReader)
+                .add(containerInListReader)
+        .build();
+    }
+
+    @Test
+    public void testReadAll() throws Exception {
+        final ReadableDataTreeDelegator readableDataTreeDelegator =
+                new ReadableDataTreeDelegator(serializer, schemaContext, registry, contextBroker);
+        final CheckedFuture<Optional<NormalizedNode<?, ?>>, org.opendaylight.controller.md.sal.common.api.data.ReadFailedException>
+                read = readableDataTreeDelegator.read(YangInstanceIdentifier.EMPTY);
+
+        final Multimap<InstanceIdentifier<? extends DataObject>, ? extends DataObject> readAll =
+                toBinding(read.checkedGet().get());
+        assertThat(readAll.size(), is(1));
+        assertEquals(readEntireSubtree(), readAll.get(Ids.CONTAINER_WITH_LIST_ID).stream().findFirst().get());
+    }
+
+    private void readSubtree(final InstanceIdentifier<ContainerWithList> id,
+                             final ContainerWithListBuilder b,
+                             final ReadContext readContext) {
+        b.setListInContainer(Lists.newArrayList(1L, 2L).stream()
+                .map(l -> new ListInContainerBuilder().setId(l).build())
+                .collect(Collectors.toList()));
+    }
+
+    private ContainerWithList readEntireSubtree() {
+        final ContainerWithListBuilder b = new ContainerWithListBuilder();
+        b.setListInContainer(Lists.newArrayList(1L, 2L).stream()
+                .map(l -> {
+                    final ContainerInListBuilder containerInListBuilder = new ContainerInListBuilder();
+                    readContainerInList(
+                            Ids.CONTAINER_WITH_LIST_ID.child(ListInContainer.class, new ListInContainerKey(l)).child(ContainerInList.class),
+                            containerInListBuilder,
+                            ctx);
+                    return new ListInContainerBuilder().setId(l).setContainerInList(containerInListBuilder.build()).build();
+                })
+                .collect(Collectors.toList()));
+        return b.build();
+    }
+
+    private void readContainerInList(final InstanceIdentifier<ContainerInList> id,
+                                     final ContainerInListBuilder b,
+                                     final ReadContext readContext) {
+        b.setName(id.firstKeyOf(ListInContainer.class).getId().toString());
+    }
+}
index 51fc227..b3a06ec 100644 (file)
@@ -28,7 +28,6 @@ import static org.mockito.Mockito.when;
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
-import com.google.common.util.concurrent.Futures;
 import io.fd.honeycomb.v3po.data.DataModification;
 import io.fd.honeycomb.v3po.translate.util.write.registry.FlatWriterRegistryBuilder;
 import io.fd.honeycomb.v3po.translate.write.WriteContext;
@@ -39,14 +38,8 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
-import javassist.ClassPool;
-import org.junit.Before;
 import org.junit.Test;
 import org.mockito.InOrder;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.$YangModuleInfoImpl;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ComplexAugment;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ComplexAugmentBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithChoice;
@@ -72,13 +65,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.simple.container.ComplexAugmentContainerBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.some.attributes.ContainerFromGrouping;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.some.attributes.ContainerFromGroupingBuilder;
-import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
-import org.opendaylight.yangtools.binding.data.codec.gen.impl.DataObjectSerializerGenerator;
-import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
-import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
-import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
-import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
-import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
@@ -87,61 +73,28 @@ 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 org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
 /**
- * Testing honeycomb writes from data tree up to mocked writers
+ * Testing honeycomb writes from data tree up to mocked writers.
  */
-public class HoneycombWriteInfraTest {
+public class HoneycombWriteInfraTest extends AbstractInfraTest {
 
     private TipProducingDataTree dataTree;
-    private BindingNormalizedNodeSerializer serializer;
     private WriterRegistry writerRegistry;
-    private SchemaContext schemaContext;
-
-    @Mock
-    private org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction ctxTx;
-    @Mock
-    private org.opendaylight.controller.md.sal.binding.api.DataBroker contextBroker;
-
-    // Simple container
-    // ORDER = 3
-    static final InstanceIdentifier<SimpleContainer> SIMPLE_CONTAINER_ID = InstanceIdentifier.create(SimpleContainer.class);
-    Writer<SimpleContainer> simpleContainerWriter = mockWriter(SIMPLE_CONTAINER_ID);
-    // UNORDERED
-    static final InstanceIdentifier<ComplexAugment> COMPLEX_AUGMENT_ID = SIMPLE_CONTAINER_ID.augmentation(ComplexAugment.class);
-    Writer<ComplexAugment> complexAugmentWriter = mockWriter(COMPLEX_AUGMENT_ID);
-    // 1
-    static final InstanceIdentifier<ComplexAugmentContainer> COMPLEX_AUGMENT_CONTAINER_ID = COMPLEX_AUGMENT_ID.child(ComplexAugmentContainer.class);
-    Writer<ComplexAugmentContainer> complexAugmentContainerWriter = mockWriter(COMPLEX_AUGMENT_CONTAINER_ID);
-    // 2
-    static final InstanceIdentifier<SimpleAugment> SIMPLE_AUGMENT_ID = SIMPLE_CONTAINER_ID.augmentation(SimpleAugment.class);
-    Writer<SimpleAugment> simpleAugmentWriter = mockWriter(SIMPLE_AUGMENT_ID);
-
-    // Container with list
-    // 9
-    static final InstanceIdentifier<ContainerWithList> CONTAINER_WITH_LIST_ID = InstanceIdentifier.create(ContainerWithList.class);
-    Writer<ContainerWithList> containerWithListWriter = mockWriter(CONTAINER_WITH_LIST_ID);
-    // 7
-    static final InstanceIdentifier<ListInContainer> LIST_IN_CONTAINER_ID = CONTAINER_WITH_LIST_ID.child(ListInContainer.class);
-    Writer<ListInContainer> listInContainerWriter = mockWriter(LIST_IN_CONTAINER_ID);
-    // 8
-    static final InstanceIdentifier<ContainerInList> CONTAINER_IN_LIST_ID = LIST_IN_CONTAINER_ID.child(ContainerInList.class);
-    Writer<ContainerInList> containerInListWriter = mockWriter(CONTAINER_IN_LIST_ID);
-    // 6
-    static final InstanceIdentifier<NestedList> NESTED_LIST_ID = CONTAINER_IN_LIST_ID.child(NestedList.class);
-    Writer<NestedList> nestedListWriter = mockWriter(NESTED_LIST_ID);
-
-    // Container with choice
-    // 4
-    static final InstanceIdentifier<ContainerWithChoice> CONTAINER_WITH_CHOICE_ID = InstanceIdentifier.create(ContainerWithChoice.class);
-    Writer<ContainerWithChoice> containerWithChoiceWriter = mockWriter(CONTAINER_WITH_CHOICE_ID);
-    // 5
-    static final InstanceIdentifier<ContainerFromGrouping> CONTAINER_FROM_GROUPING_ID = CONTAINER_WITH_CHOICE_ID.child(ContainerFromGrouping.class);
-    Writer<ContainerFromGrouping> containerFromGroupingWriter = mockWriter(CONTAINER_FROM_GROUPING_ID);
-    // 2
-    static final InstanceIdentifier<C3> C3_ID = CONTAINER_WITH_CHOICE_ID.child(C3.class);
-    Writer<C3> c3Writer = mockWriter(C3_ID);
+
+    Writer<SimpleContainer> simpleContainerWriter = mockWriter(Ids.SIMPLE_CONTAINER_ID);
+    Writer<ComplexAugment> complexAugmentWriter = mockWriter(Ids.COMPLEX_AUGMENT_ID);
+    Writer<ComplexAugmentContainer> complexAugmentContainerWriter = mockWriter(Ids.COMPLEX_AUGMENT_CONTAINER_ID);
+    Writer<SimpleAugment> simpleAugmentWriter = mockWriter(Ids.SIMPLE_AUGMENT_ID);
+
+    Writer<ContainerWithList> containerWithListWriter = mockWriter(Ids.CONTAINER_WITH_LIST_ID);
+    Writer<ListInContainer> listInContainerWriter = mockWriter(Ids.LIST_IN_CONTAINER_ID);
+    Writer<ContainerInList> containerInListWriter = mockWriter(Ids.CONTAINER_IN_LIST_ID);
+    Writer<NestedList> nestedListWriter = mockWriter(Ids.NESTED_LIST_ID);
+
+    Writer<ContainerWithChoice> containerWithChoiceWriter = mockWriter(Ids.CONTAINER_WITH_CHOICE_ID);
+    Writer<ContainerFromGrouping> containerFromGroupingWriter = mockWriter(Ids.CONTAINER_FROM_GROUPING_ID);
+    Writer<C3> c3Writer = mockWriter(Ids.C3_ID);
 
 
     private static <D extends DataObject> Writer<D> mockWriter(final InstanceIdentifier<D> id) {
@@ -150,13 +103,8 @@ public class HoneycombWriteInfraTest {
         return mock;
     }
 
-    @Before
-    public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        when(contextBroker.newReadWriteTransaction()).thenReturn(ctxTx);
-        when(ctxTx.submit()).thenReturn(Futures.immediateCheckedFuture(null));
-
-        initSerializer();
+    @Override
+    void postSetup() {
         initDataTree();
         initWriterRegistry();
     }
@@ -166,33 +114,19 @@ public class HoneycombWriteInfraTest {
         dataTree.setSchemaContext(schemaContext);
     }
 
-    private void initSerializer() {
-        final ModuleInfoBackedContext moduleInfoBackedContext = ModuleInfoBackedContext.create();
-        moduleInfoBackedContext.addModuleInfos(Collections.singleton($YangModuleInfoImpl.getInstance()));
-        schemaContext = moduleInfoBackedContext.tryToCreateSchemaContext().get();
-
-        final DataObjectSerializerGenerator serializerGenerator = new StreamWriterGenerator(JavassistUtils.forClassPool(
-                ClassPool.getDefault()));
-        final BindingNormalizedNodeCodecRegistry codecRegistry = new BindingNormalizedNodeCodecRegistry(serializerGenerator);
-        serializer = new BindingToNormalizedNodeCodec(moduleInfoBackedContext, codecRegistry);
-        final BindingRuntimeContext ctx =
-                BindingRuntimeContext.create(moduleInfoBackedContext, schemaContext);
-        codecRegistry.onBindingRuntimeContextUpdated(ctx);
-    }
-
     private void initWriterRegistry() {
         writerRegistry = new FlatWriterRegistryBuilder()
                 .add(complexAugmentWriter) // unordered
                 .add(nestedListWriter) // 6
-                .addAfter(listInContainerWriter, NESTED_LIST_ID) // 7
-                .addAfter(containerInListWriter, LIST_IN_CONTAINER_ID) // 8
-                .addAfter(containerWithListWriter, CONTAINER_IN_LIST_ID) // 9
-                .addBefore(containerFromGroupingWriter, NESTED_LIST_ID) // 5
-                .addBefore(containerWithChoiceWriter, CONTAINER_FROM_GROUPING_ID) // 4
-                .addBefore(simpleContainerWriter, CONTAINER_WITH_CHOICE_ID) // 3
-                .addBefore(c3Writer, SIMPLE_CONTAINER_ID) // 2
-                .addBefore(simpleAugmentWriter, SIMPLE_CONTAINER_ID) // 2
-                .addBefore(complexAugmentContainerWriter, Sets.newHashSet(C3_ID, SIMPLE_AUGMENT_ID)) // 1
+                .addAfter(listInContainerWriter, Ids.NESTED_LIST_ID) // 7
+                .addAfter(containerInListWriter, Ids.LIST_IN_CONTAINER_ID) // 8
+                .addAfter(containerWithListWriter, Ids.CONTAINER_IN_LIST_ID) // 9
+                .addBefore(containerFromGroupingWriter, Ids.NESTED_LIST_ID) // 5
+                .addBefore(containerWithChoiceWriter, Ids.CONTAINER_FROM_GROUPING_ID) // 4
+                .addBefore(simpleContainerWriter, Ids.CONTAINER_WITH_CHOICE_ID) // 3
+                .addBefore(c3Writer, Ids.SIMPLE_CONTAINER_ID) // 2
+                .addBefore(simpleAugmentWriter, Ids.SIMPLE_CONTAINER_ID) // 2
+                .addBefore(complexAugmentContainerWriter, Sets.newHashSet(Ids.C3_ID, Ids.SIMPLE_AUGMENT_ID)) // 1
                 .build();
     }
 
@@ -206,7 +140,7 @@ public class HoneycombWriteInfraTest {
                 .build();
 
         final Map.Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> normalizedNode =
-                serializer.toNormalizedNode(SIMPLE_CONTAINER_ID, data);
+                serializer.toNormalizedNode(Ids.SIMPLE_CONTAINER_ID, data);
         dataModification.write(normalizedNode.getKey(), normalizedNode.getValue());
 
         dataModification.commit();
@@ -239,29 +173,29 @@ public class HoneycombWriteInfraTest {
         // verify(complexAugmentWriter).update(eq(COMPLEX_AUGMENT_ID), eq(null), eq(getComplexAugment()), any(WriteContext.class));
         // 1
         inOrder.verify(complexAugmentContainerWriter)
-                .update(eq(COMPLEX_AUGMENT_CONTAINER_ID), eq(null), eq(getComplexAugmentContainer()), any(WriteContext.class));
+                .update(eq(Ids.COMPLEX_AUGMENT_CONTAINER_ID), eq(null), eq(getComplexAugmentContainer()), any(WriteContext.class));
         // 2
         inOrder.verify(c3Writer)
-                .update(eq(C3_ID), eq(null), eq(getC3()), any(WriteContext.class));
+                .update(eq(Ids.C3_ID), eq(null), eq(getC3()), any(WriteContext.class));
         // 2
         verify(simpleAugmentWriter)
-                .update(eq(SIMPLE_AUGMENT_ID), eq(null), eq(getSimpleAugment()), any(WriteContext.class));
+                .update(eq(Ids.SIMPLE_AUGMENT_ID), eq(null), eq(getSimpleAugment()), any(WriteContext.class));
         // 3
         inOrder.verify(simpleContainerWriter)
-                .update(eq(SIMPLE_CONTAINER_ID), eq(null), eq(getSimpleContainer()), any(WriteContext.class));
+                .update(eq(Ids.SIMPLE_CONTAINER_ID), eq(null), eq(getSimpleContainer()), any(WriteContext.class));
         // 4
         inOrder.verify(containerWithChoiceWriter)
-                .update(eq(CONTAINER_WITH_CHOICE_ID), eq(null), eq(getContainerWithChoiceWithComplexCase()), any(WriteContext.class));
+                .update(eq(Ids.CONTAINER_WITH_CHOICE_ID), eq(null), eq(getContainerWithChoiceWithComplexCase()), any(WriteContext.class));
         // 5
         inOrder.verify(containerFromGroupingWriter)
-                .update(eq(CONTAINER_FROM_GROUPING_ID), eq(null), eq(getContainerFromGrouping()), any(WriteContext.class));
+                .update(eq(Ids.CONTAINER_FROM_GROUPING_ID), eq(null), eq(getContainerFromGrouping()), any(WriteContext.class));
 
         final KeyedInstanceIdentifier<ListInContainer, ListInContainerKey> keyedListInContainer1 =
-                CONTAINER_WITH_LIST_ID.child(ListInContainer.class, new ListInContainerKey((long) 1));
+                Ids.CONTAINER_WITH_LIST_ID.child(ListInContainer.class, new ListInContainerKey((long) 1));
         final KeyedInstanceIdentifier<NestedList, NestedListKey> keyedNestedList1 =
                 keyedListInContainer1.child(ContainerInList.class).child(NestedList.class, new NestedListKey("1"));
         final KeyedInstanceIdentifier<ListInContainer, ListInContainerKey> keyedListInContainer2 =
-                CONTAINER_WITH_LIST_ID.child(ListInContainer.class, new ListInContainerKey((long) 2));
+                Ids.CONTAINER_WITH_LIST_ID.child(ListInContainer.class, new ListInContainerKey((long) 2));
         final KeyedInstanceIdentifier<NestedList, NestedListKey> keyedNestedList2 =
                 keyedListInContainer2.child(ContainerInList.class).child(NestedList.class, new NestedListKey("2"));
 
@@ -332,11 +266,11 @@ public class HoneycombWriteInfraTest {
         final InOrder inOrder = inOrder(orderedWriters);
 
         final KeyedInstanceIdentifier<ListInContainer, ListInContainerKey> keyedListInContainer1 =
-                CONTAINER_WITH_LIST_ID.child(ListInContainer.class, new ListInContainerKey((long) 1));
+                Ids.CONTAINER_WITH_LIST_ID.child(ListInContainer.class, new ListInContainerKey((long) 1));
         final KeyedInstanceIdentifier<NestedList, NestedListKey> keyedNestedList1 =
                 keyedListInContainer1.child(ContainerInList.class).child(NestedList.class, new NestedListKey("1"));
         final KeyedInstanceIdentifier<ListInContainer, ListInContainerKey> keyedListInContainer2 =
-                CONTAINER_WITH_LIST_ID.child(ListInContainer.class, new ListInContainerKey((long) 2));
+                Ids.CONTAINER_WITH_LIST_ID.child(ListInContainer.class, new ListInContainerKey((long) 2));
         final KeyedInstanceIdentifier<NestedList, NestedListKey> keyedNestedList2 =
                 keyedListInContainer2.child(ContainerInList.class).child(NestedList.class, new NestedListKey("2"));
 
@@ -360,22 +294,22 @@ public class HoneycombWriteInfraTest {
                 .update(eq(keyedNestedList2), eq(getSingleNestedList("2")), eq(null), any(WriteContext.class));
         // 4
         inOrder.verify(containerFromGroupingWriter)
-                .update(eq(CONTAINER_FROM_GROUPING_ID), eq(getContainerFromGrouping()), eq(null), any(WriteContext.class));
+                .update(eq(Ids.CONTAINER_FROM_GROUPING_ID), eq(getContainerFromGrouping()), eq(null), any(WriteContext.class));
         // 5
         inOrder.verify(containerWithChoiceWriter)
-                .update(eq(CONTAINER_WITH_CHOICE_ID), eq(getContainerWithChoiceWithComplexCase()), eq(null), any(WriteContext.class));
+                .update(eq(Ids.CONTAINER_WITH_CHOICE_ID), eq(getContainerWithChoiceWithComplexCase()), eq(null), any(WriteContext.class));
         // 6
         inOrder.verify(simpleContainerWriter)
-                .update(eq(SIMPLE_CONTAINER_ID), eq(getSimpleContainer()), eq(null), any(WriteContext.class));
+                .update(eq(Ids.SIMPLE_CONTAINER_ID), eq(getSimpleContainer()), eq(null), any(WriteContext.class));
         // 7
         verify(simpleAugmentWriter)
-                .update(eq(SIMPLE_AUGMENT_ID), eq(getSimpleAugment()), eq(null), any(WriteContext.class));
+                .update(eq(Ids.SIMPLE_AUGMENT_ID), eq(getSimpleAugment()), eq(null), any(WriteContext.class));
         // 8
         inOrder.verify(c3Writer)
-                .update(eq(C3_ID), eq(getC3()), eq(null), any(WriteContext.class));
+                .update(eq(Ids.C3_ID), eq(getC3()), eq(null), any(WriteContext.class));
         // 9
         inOrder.verify(complexAugmentContainerWriter)
-                .update(eq(COMPLEX_AUGMENT_CONTAINER_ID), eq(getComplexAugmentContainer()), eq(null), any(WriteContext.class));
+                .update(eq(Ids.COMPLEX_AUGMENT_CONTAINER_ID), eq(getComplexAugmentContainer()), eq(null), any(WriteContext.class));
 
         for (Writer<?> orderedWriter : orderedWriters) {
             verify(orderedWriter).getManagedDataObjectType();
@@ -385,12 +319,12 @@ public class HoneycombWriteInfraTest {
 
     private void writeContainerWithList(final DataModification dataModification) {
         final Map.Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> normalizedNode =
-                serializer.toNormalizedNode(CONTAINER_WITH_LIST_ID, getContainerWithList());
+                serializer.toNormalizedNode(Ids.CONTAINER_WITH_LIST_ID, getContainerWithList());
         dataModification.write(normalizedNode.getKey(), normalizedNode.getValue());
     }
 
     private void deleteContainerWithList(final DataModification dataModification) {
-        dataModification.delete(serializer.toYangInstanceIdentifier(CONTAINER_WITH_LIST_ID));
+        dataModification.delete(serializer.toYangInstanceIdentifier(Ids.CONTAINER_WITH_LIST_ID));
     }
 
     private ContainerWithList getContainerWithList() {
@@ -442,13 +376,13 @@ public class HoneycombWriteInfraTest {
 
 
     private void deleteContainerWithChoice(final DataModification dataModification) {
-        dataModification.delete(serializer.toYangInstanceIdentifier(CONTAINER_WITH_CHOICE_ID));
+        dataModification.delete(serializer.toYangInstanceIdentifier(Ids.CONTAINER_WITH_CHOICE_ID));
     }
 
     private void writeContainerWithChoice(final DataModification dataModification,
                                           final ContainerWithChoice containerWithChoice) {
         final Map.Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> normalizedNode =
-                serializer.toNormalizedNode(CONTAINER_WITH_CHOICE_ID, containerWithChoice);
+                serializer.toNormalizedNode(Ids.CONTAINER_WITH_CHOICE_ID, containerWithChoice);
         dataModification.write(normalizedNode.getKey(), normalizedNode.getValue());
     }
 
@@ -475,7 +409,7 @@ public class HoneycombWriteInfraTest {
 
     private void writeContainerFromGrouping(final DataModification dataModification) {
         final Map.Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> normalizedNode =
-                serializer.toNormalizedNode(CONTAINER_FROM_GROUPING_ID, getContainerFromGrouping());
+                serializer.toNormalizedNode(Ids.CONTAINER_FROM_GROUPING_ID, getContainerFromGrouping());
         dataModification.write(normalizedNode.getKey(), normalizedNode.getValue());
     }
 
@@ -488,13 +422,13 @@ public class HoneycombWriteInfraTest {
 
     private void writeSimpleContainer(final DataModification dataModification) {
         final Map.Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> normalizedNode =
-                serializer.toNormalizedNode(SIMPLE_CONTAINER_ID, getSimpleContainer());
+                serializer.toNormalizedNode(Ids.SIMPLE_CONTAINER_ID, getSimpleContainer());
         dataModification.write(normalizedNode.getKey(), normalizedNode.getValue());
     }
 
     private void deleteSimpleContainer(final DataModification dataModification) {
         final YangInstanceIdentifier yangId =
-                serializer.toYangInstanceIdentifier(SIMPLE_CONTAINER_ID);
+                serializer.toYangInstanceIdentifier(Ids.SIMPLE_CONTAINER_ID);
         dataModification.delete(yangId);
     }
 
@@ -540,7 +474,7 @@ public class HoneycombWriteInfraTest {
     public void testSubtreeWriter() throws Exception {
         writerRegistry = new FlatWriterRegistryBuilder()
                 // Handles also container from grouping
-                .subtreeAdd(Sets.newHashSet(CONTAINER_FROM_GROUPING_ID), containerWithChoiceWriter)
+                .subtreeAdd(Sets.newHashSet(Ids.CONTAINER_FROM_GROUPING_ID), containerWithChoiceWriter)
                 .build();
 
         final ModifiableDataTreeDelegator modifiableDataTreeDelegator =
@@ -556,7 +490,7 @@ public class HoneycombWriteInfraTest {
 
         verify(containerWithChoiceWriter, atLeastOnce()).getManagedDataObjectType();
         verify(containerWithChoiceWriter)
-                .update(eq(CONTAINER_WITH_CHOICE_ID), eq(null), eq(containerWithChoice), any(WriteContext.class));
+                .update(eq(Ids.CONTAINER_WITH_CHOICE_ID), eq(null), eq(containerWithChoice), any(WriteContext.class));
         verifyNoMoreInteractions(containerWithChoiceWriter);
 
         // Test delete sub-node
@@ -567,7 +501,7 @@ public class HoneycombWriteInfraTest {
 
         verify(containerWithChoiceWriter, atLeastOnce()).getManagedDataObjectType();
         verify(containerWithChoiceWriter)
-                .update(eq(CONTAINER_WITH_CHOICE_ID), eq(containerWithChoice), eq(containerWithChoiceEmpty), any(WriteContext.class));
+                .update(eq(Ids.CONTAINER_WITH_CHOICE_ID), eq(containerWithChoice), eq(containerWithChoiceEmpty), any(WriteContext.class));
         verifyNoMoreInteractions(containerWithChoiceWriter);
 
         // Test write with subtree node that's not handled by subtree writer
@@ -582,6 +516,6 @@ public class HoneycombWriteInfraTest {
     }
 
     private void deleteContainerFromGrouping(final DataModification dataModification) {
-        dataModification.delete(serializer.toYangInstanceIdentifier(CONTAINER_FROM_GROUPING_ID));
+        dataModification.delete(serializer.toYangInstanceIdentifier(Ids.CONTAINER_FROM_GROUPING_ID));
     }
 }
\ No newline at end of file
diff --git a/v3po/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/Ids.java b/v3po/it/it-test/src/test/java/io/fd/honeycomb/v3po/data/impl/Ids.java
new file mode 100644 (file)
index 0000000..200f50c
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.data.impl;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ComplexAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithChoice;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.ContainerWithList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.SimpleContainer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.choice.choice.c3.C3;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.ListInContainer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.ContainerInList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.container.with.list.list.in.container.container.in.list.NestedList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.simple.container.ComplexAugmentContainer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hc.test.rev150105.some.attributes.ContainerFromGrouping;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Instance identifiers referencing all complex nodes within IT test-model.
+ */
+interface Ids {
+
+    // Simple container
+    // ORDER = 3
+    InstanceIdentifier<SimpleContainer> SIMPLE_CONTAINER_ID = InstanceIdentifier.create(SimpleContainer.class);
+    // 2
+    InstanceIdentifier<SimpleAugment> SIMPLE_AUGMENT_ID = SIMPLE_CONTAINER_ID.augmentation(SimpleAugment.class);
+    // UNORDERED
+    InstanceIdentifier<ComplexAugment> COMPLEX_AUGMENT_ID = SIMPLE_CONTAINER_ID.augmentation(ComplexAugment.class);
+    // 1
+    InstanceIdentifier<ComplexAugmentContainer> COMPLEX_AUGMENT_CONTAINER_ID = COMPLEX_AUGMENT_ID.child(ComplexAugmentContainer.class);
+    // Container with list
+    // 9
+    InstanceIdentifier<ContainerWithList> CONTAINER_WITH_LIST_ID = InstanceIdentifier.create(ContainerWithList.class);
+    // 7
+    InstanceIdentifier<ListInContainer> LIST_IN_CONTAINER_ID = CONTAINER_WITH_LIST_ID.child(ListInContainer.class);
+    // 8
+    InstanceIdentifier<ContainerInList> CONTAINER_IN_LIST_ID = LIST_IN_CONTAINER_ID.child(ContainerInList.class);
+    // 6
+    InstanceIdentifier<NestedList> NESTED_LIST_ID = CONTAINER_IN_LIST_ID.child(NestedList.class);
+    // Container with choice
+    // 4
+    InstanceIdentifier<ContainerWithChoice> CONTAINER_WITH_CHOICE_ID = InstanceIdentifier.create(ContainerWithChoice.class);
+    // 2
+    InstanceIdentifier<C3> C3_ID = CONTAINER_WITH_CHOICE_ID.child(C3.class);
+    // 5
+    InstanceIdentifier<ContainerFromGrouping> CONTAINER_FROM_GROUPING_ID = CONTAINER_WITH_CHOICE_ID.child(ContainerFromGrouping.class);
+}
index 204c5c0..e13b500 100644 (file)
@@ -11,7 +11,8 @@ module hc-test {
     prefix "ext";
   }
 
-  // ORDER 3
+  // WRITE ORDER 3
+  // READ ORDER 1
   container simple-container {
     leaf simple-container-name {
       type string;
@@ -23,7 +24,7 @@ module hc-test {
         type string;
     }
 
-    // ORDER 5
+    // WRITE ORDER 5
     container container-from-grouping {
         leaf leaf-in-container-from-grouping {
             type int32;
@@ -31,25 +32,31 @@ module hc-test {
     }
   }
 
-  // ORDER 9 (no real attributes though)
+  // WRITE ORDER 9 (no real attributes though)
+  // READ ORDER 2
   container container-with-list {
-    // ORDER 7
+    // WRITE ORDER 7
+    // READ ORDER 2.1
     list list-in-container {
         key "id";
+        ordered-by "user";
 
         leaf id {
             type uint32;
         }
 
-        // ORDER 8
+        // WRITE ORDER 8
+        // READ ORDER 2.1.1
         container container-in-list {
             leaf name {
                 type string;
             }
 
-            // ORDER 6
+            // WRITE ORDER 6
+            // READ ORDER 2.1.1.1
             list nested-list {
                 key "nested-id";
+                ordered-by "user";
 
                 leaf nested-id {
                     type string;
@@ -63,7 +70,7 @@ module hc-test {
     }
   }
 
-  // ORDER 4
+  // WRITE ORDER 4
   container container-with-choice {
     leaf name {
         type string;
@@ -80,7 +87,7 @@ module hc-test {
             type string;
         }
 
-        // ORDER: 2
+        // WRITE ORDER: 2
         container c3 {
             leaf name {
                 type string;
@@ -89,7 +96,8 @@ module hc-test {
     }
   }
 
-  // ORDER: 2
+  // WRITE ORDER: 2
+  // READ ORDER 1.1
   augment "/hct:simple-container" {
     ext:augment-identifier "simple-augment";
 
@@ -98,11 +106,13 @@ module hc-test {
     }
   }
 
-  // UNORDERED
+  // WRITE UNORDERED
+  // READ ORDER 1.2
   augment "/hct:simple-container" {
     ext:augment-identifier "complex-augment";
 
-    // ORDER: 1
+    // WRITE ORDER: 1
+    // READ ORDER 1.2.1
     container complex-augment-container {
         leaf some-leaf {
             type string;
index 6d6d52a..61472f8 100644 (file)
@@ -24,10 +24,15 @@ import javax.annotation.Nonnull;
  * Factory producing readers for {@link ModifiableReaderRegistryBuilder}.
  */
 @Beta
-public interface ReaderFactory {
+public interface ReaderFactory extends AutoCloseable {
 
     /**
      * Initialize 1 or more readers and add them to provided registry.
      */
     void init(@Nonnull ModifiableReaderRegistryBuilder registry);
+
+    @Override
+    default void close() {
+        // NOOP TODO allow unregister
+    }
 }
index dfcffa4..ffc76a0 100644 (file)
@@ -24,10 +24,15 @@ import javax.annotation.Nonnull;
  * Factory producing writers for {@link ModifiableWriterRegistryBuilder}.
  */
 @Beta
-public interface WriterFactory {
+public interface WriterFactory extends AutoCloseable {
 
     /**
      * Initialize 1 or more writers and add them to provided registry.
      */
     void init(@Nonnull ModifiableWriterRegistryBuilder registry);
+
+    @Override
+    default void close() {
+        // NOOP TODO allow unregister
+    }
 }
index 54dad55..defb2e5 100644 (file)
@@ -91,7 +91,10 @@ public final class GenericListReader<C extends DataObject & Identifiable<K>, K e
     @Override
     public List<K> getAllIds(@Nonnull final InstanceIdentifier<C> id, @Nonnull final ReadContext ctx)
             throws ReadFailedException {
-        return customizer.getAllIds(id, ctx);
+        LOG.trace("{}: Getting all list ids", this);
+        final List<K> allIds = customizer.getAllIds(id, ctx);
+        LOG.debug("{}: All list ids: {}", this, allIds);
+        return allIds;
     }
 
     @Override
index ba9d8e1..2a565d9 100644 (file)
@@ -117,7 +117,7 @@ public final class RWUtils {
     }
 
     /**
-     * Create a map from a collection, checking for duplicity in the process
+     * Create an ordered map from a collection, checking for duplicity in the process.
      */
     @Nonnull
     public static <K, V> Map<K, V> uniqueLinkedIndex(@Nonnull final Collection<V> values, @Nonnull final Function<? super V, K> keyFunction) {
@@ -152,6 +152,9 @@ public final class RWUtils {
 
     /**
      * Transform a keyed instance identifier into a wildcarded one.
+     * <p/>
+     * ! This has to be called also for wildcarded List instance identifiers
+     * due to weird behavior of equals in InstanceIdentifier !
      */
     @SuppressWarnings("unchecked")
     public static <D extends DataObject> InstanceIdentifier<D> makeIidWildcarded(final InstanceIdentifier<D> id) {
@@ -162,6 +165,19 @@ public final class RWUtils {
         return (InstanceIdentifier<D>) InstanceIdentifier.create(transformedPathArguments);
     }
 
+    /**
+     * Transform a keyed instance identifier into a wildcarded one, keeping keys except the last item.
+     */
+    @SuppressWarnings("unchecked")
+    public static <D extends DataObject> InstanceIdentifier<D> makeIidLastWildcarded(final InstanceIdentifier<D> id) {
+        final InstanceIdentifier.Item<D> wildcardedItem = new InstanceIdentifier.Item<>(id.getTargetType());
+        final Iterable<InstanceIdentifier.PathArgument> pathArguments = id.getPathArguments();
+        return (InstanceIdentifier<D>) InstanceIdentifier.create(
+                Iterables.concat(
+                        Iterables.limit(pathArguments, Iterables.size(pathArguments) - 1),
+                        Collections.singleton(wildcardedItem)));
+    }
+
     private static InstanceIdentifier.PathArgument cleanPathArgumentFromKeys(final InstanceIdentifier.PathArgument pathArgument) {
         return pathArgument instanceof InstanceIdentifier.IdentifiableItem<?, ?>
                 ? new InstanceIdentifier.Item<>(pathArgument.getType())
index ea0b3b2..728c4f8 100644 (file)
@@ -44,7 +44,7 @@ public final class ReflectionUtils {
                                                     @Nonnull final List<Class<?>> paramTypes,
                                                     @Nonnull final Class<?> retType) {
         for (Method method : managedType.getMethods()) {
-            if(isMethodMatch(prefix, paramTypes, retType, method)) {
+            if (isMethodMatch(prefix, paramTypes, retType, method)) {
                 return Optional.of(method);
             }
         }
diff --git a/v3po/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/ReflexiveListReaderCustomizer.java b/v3po/translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/util/read/ReflexiveListReaderCustomizer.java
new file mode 100644 (file)
index 0000000..8ad323c
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.translate.util.read;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.v3po.translate.spi.read.ListReaderCustomizer;
+import io.fd.honeycomb.v3po.translate.util.ReflectionUtils;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.List;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+
+/**
+ * Might be slow !
+ */
+public abstract class ReflexiveListReaderCustomizer<C extends DataObject & Identifiable<K>, K extends Identifier<C>, B extends Builder<C>>
+        extends ReflexiveReaderCustomizer<C, B>
+        implements ListReaderCustomizer<C, K, B> {
+
+
+    public ReflexiveListReaderCustomizer(final Class<C> typeClass, final Class<B> builderClass) {
+        super(typeClass, builderClass);
+    }
+
+    @Override
+    public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final C readValue) {
+        merge(parentBuilder, Collections.singletonList(readValue));
+    }
+
+    @Override
+    public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final List<C> readData) {
+        final Optional<Method> method =
+                ReflectionUtils.findMethodReflex(parentBuilder.getClass(), "set" + getTypeClass().getSimpleName(),
+                        Collections.singletonList(List.class), parentBuilder.getClass());
+
+        checkArgument(method.isPresent(), "Unable to set %s to %s", readData, parentBuilder);
+
+        try {
+            method.get().invoke(parentBuilder, readData);
+        } catch (IllegalAccessException | InvocationTargetException e) {
+            throw new IllegalArgumentException("Unable to set " + readData + " to " + parentBuilder, e);
+        }
+    }
+}
index 51725e7..2b2d930 100644 (file)
@@ -28,7 +28,7 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
  * <p/>
  * Might be slow due to reflection !
  */
-public final class ReflexiveReader<C extends DataObject, B extends Builder<C>> extends AbstractGenericReader<C, B> {
+public class ReflexiveReader<C extends DataObject, B extends Builder<C>> extends AbstractGenericReader<C, B> {
 
     private final ReflexiveReaderCustomizer<C, B> customizer;
 
index f9efca3..a6b9bf0 100644 (file)
@@ -33,7 +33,7 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 /**
  * Might be slow !
  */
-final class ReflexiveReaderCustomizer<C extends DataObject, B extends Builder<C>> extends NoopReaderCustomizer<C, B> {
+class ReflexiveReaderCustomizer<C extends DataObject, B extends Builder<C>> extends NoopReaderCustomizer<C, B> {
 
     private final Class<C> typeClass;
     private final Class<B> builderClass;
index 64ecaf0..aa9b2dc 100644 (file)
@@ -18,6 +18,7 @@ package io.fd.honeycomb.v3po.translate.util.read.registry;
 
 import static com.google.common.base.Preconditions.checkArgument;
 
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
@@ -53,6 +54,11 @@ class CompositeReader<D extends DataObject, B extends Builder<D>> extends Abstra
         this.childReaders = childReaders;
     }
 
+    @VisibleForTesting
+    ImmutableMap<Class<?>, Reader<? extends DataObject, ? extends Builder<?>>> getChildReaders() {
+        return childReaders;
+    }
+
     @SuppressWarnings("unchecked")
     public static <D extends DataObject> InstanceIdentifier<D> appendTypeToId(
         final InstanceIdentifier<? extends DataObject> parentId, final InstanceIdentifier<D> type) {
@@ -66,11 +72,14 @@ class CompositeReader<D extends DataObject, B extends Builder<D>> extends Abstra
     public Optional<? extends DataObject> read(@Nonnull final InstanceIdentifier<? extends DataObject> id,
                                                @Nonnull final ReadContext ctx) throws ReadFailedException {
         if (shouldReadCurrent(id)) {
+            LOG.trace("{}: Reading current: {}", this, id);
             return readCurrent((InstanceIdentifier<D>) id, ctx);
         } else if (shouldDelegateToChild(id)) {
+            LOG.trace("{}: Reading child: {}", this, id);
             return readSubtree(id, ctx);
         } else {
             // Fallback
+            LOG.trace("{}: Delegating read: {}", this, id);
             return delegate.read(id, ctx);
         }
     }
@@ -95,10 +104,11 @@ class CompositeReader<D extends DataObject, B extends Builder<D>> extends Abstra
     @SuppressWarnings("unchecked")
     private void readChildren(final InstanceIdentifier<D> id, @Nonnull final ReadContext ctx, final B builder)
             throws ReadFailedException {
+        LOG.debug("{}: Reading children: {}", this, childReaders.keySet());
         for (Reader child : childReaders.values()) {
-            LOG.debug("{}: Reading child node from: {}", this, child);
             final InstanceIdentifier childId = appendTypeToId(id, child.getManagedDataObjectType());
 
+            LOG.debug("{}: Reading child from: {}", this, child);
             if (child instanceof ListReader) {
                 final List<? extends DataObject> list = ((ListReader) child).readList(childId, ctx);
                 ((ListReader) child).merge(builder, list);
index 0a948c7..a9f606a 100644 (file)
@@ -18,6 +18,7 @@ package io.fd.honeycomb.v3po.translate.util.read.registry;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Optional;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.LinkedListMultimap;
@@ -31,6 +32,7 @@ import io.fd.honeycomb.v3po.translate.util.RWUtils;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 import javax.annotation.Nonnull;
 import org.opendaylight.yangtools.concepts.Builder;
 import org.opendaylight.yangtools.yang.binding.DataObject;
@@ -59,6 +61,11 @@ public final class CompositeReaderRegistry implements ReaderRegistry {
         this.rootReaders = RWUtils.uniqueLinkedIndex(checkNotNull(rootReaders), RWUtils.MANAGER_CLASS_FUNCTION);
     }
 
+    @VisibleForTesting
+    Map<Class<? extends DataObject>, Reader<? extends DataObject, ? extends Builder<?>>> getRootReaders() {
+        return rootReaders;
+    }
+
     @Override
     @Nonnull
     public Multimap<InstanceIdentifier<? extends DataObject>, ? extends DataObject> readAll(
@@ -101,4 +108,10 @@ public final class CompositeReaderRegistry implements ReaderRegistry {
         LOG.debug("Reading from delegate: {}", reader);
         return reader.read(id, ctx);
     }
+
+    @Override
+    public String toString() {
+        return getClass().getSimpleName()
+                + rootReaders.keySet().stream().map(Class::getSimpleName).collect(Collectors.toList());
+    }
 }
index 98fcac6..50a2065 100644 (file)
@@ -89,7 +89,7 @@ class SubtreeReader<D extends DataObject, B extends Builder<D>> implements Reade
             LOG.debug("{}: Subtree node managed by this writer requested: {}. Reading current and filtering", this, id);
             // If there's no dedicated reader, use read current
             final InstanceIdentifier<D> currentId = RWUtils.cutId(id, getManagedDataObjectType());
-            final Optional<? extends DataObject> current = read(currentId, ctx);
+            final Optional<? extends DataObject> current = delegate.read(currentId, ctx);
             // then perform post-reading filtering (return only requested sub-node)
             final Optional<? extends DataObject> readSubtree = current.isPresent()
                 ? filterSubtree(current.get(), id, getManagedDataObjectType().getTargetType())
diff --git a/v3po/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/DataObjects.java b/v3po/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/DataObjects.java
new file mode 100644 (file)
index 0000000..d823465
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.translate.util;
+
+import org.opendaylight.yangtools.yang.binding.ChildOf;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class DataObjects {
+    public interface DataObject1 extends DataObject {
+        InstanceIdentifier<DataObject1> IID = InstanceIdentifier.create(DataObject1.class);
+    }
+
+    public interface DataObject2 extends DataObject {
+        InstanceIdentifier<DataObject2> IID = InstanceIdentifier.create(DataObject2.class);
+    }
+
+    public interface DataObject3 extends DataObject {
+        InstanceIdentifier<DataObject3> IID = InstanceIdentifier.create(DataObject3.class);
+        interface DataObject31 extends DataObject, ChildOf<DataObject3> {
+            InstanceIdentifier<DataObject31> IID = DataObject3.IID.child(DataObject31.class);
+        }
+    }
+
+    public interface DataObject4 extends DataObject {
+        InstanceIdentifier<DataObject4> IID = InstanceIdentifier.create(DataObject4.class);
+        interface DataObject41 extends DataObject, ChildOf<DataObject4> {
+            InstanceIdentifier<DataObject41> IID = DataObject4.IID.child(DataObject41.class);
+            interface DataObject411 extends DataObject, ChildOf<DataObject41> {
+                InstanceIdentifier<DataObject411> IID = DataObject41.IID.child(DataObject411.class);
+            }
+        }
+
+        interface DataObject42 extends DataObject, ChildOf<DataObject4> {
+            InstanceIdentifier<DataObject42> IID = DataObject4.IID.child(DataObject42.class);
+        }
+    }
+}
diff --git a/v3po/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/read/registry/CompositeReaderRegistryBuilderTest.java b/v3po/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/read/registry/CompositeReaderRegistryBuilderTest.java
new file mode 100644 (file)
index 0000000..e57dcee
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.translate.util.read.registry;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import io.fd.honeycomb.v3po.translate.read.Reader;
+import io.fd.honeycomb.v3po.translate.read.registry.ReaderRegistry;
+import io.fd.honeycomb.v3po.translate.util.DataObjects;
+import java.util.List;
+import java.util.Map;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class CompositeReaderRegistryBuilderTest {
+
+    private Reader<DataObjects.DataObject1, Builder<DataObjects.DataObject1>> reader1 =
+            mock(DataObjects.DataObject1.class);
+    private Reader<DataObjects.DataObject2, Builder<DataObjects.DataObject2>> reader2 =
+            mock(DataObjects.DataObject2.class);
+    private Reader<DataObjects.DataObject3, Builder<DataObjects.DataObject3>> reader3 =
+            mock(DataObjects.DataObject3.class);
+    private Reader<DataObjects.DataObject3.DataObject31, Builder<DataObjects.DataObject3.DataObject31>> reader31 =
+            mock(DataObjects.DataObject3.DataObject31.class);
+
+    private Reader<DataObjects.DataObject4, Builder<DataObjects.DataObject4>> reader4 =
+            mock(DataObjects.DataObject4.class);
+    private Reader<DataObjects.DataObject4.DataObject41, Builder<DataObjects.DataObject4.DataObject41>> reader41 =
+            mock(DataObjects.DataObject4.DataObject41.class);
+    private Reader<DataObjects.DataObject4.DataObject41.DataObject411, Builder<DataObjects.DataObject4.DataObject41.DataObject411>> reader411 =
+            mock(DataObjects.DataObject4.DataObject41.DataObject411.class);
+    private Reader<DataObjects.DataObject4.DataObject42, Builder<DataObjects.DataObject4.DataObject42>> reader42 =
+            mock(DataObjects.DataObject4.DataObject42.class);
+
+    @SuppressWarnings("unchecked")
+    private <D extends DataObject> Reader<D, Builder<D>> mock(final Class<D> dataObjectType) {
+        final Reader<D, Builder<D>> mock = Mockito.mock(Reader.class);
+        try {
+            when(mock.getManagedDataObjectType())
+                    .thenReturn(((InstanceIdentifier<D>) dataObjectType.getDeclaredField("IID").get(null)));
+        } catch (IllegalAccessException | NoSuchFieldException e) {
+            throw new RuntimeException(e);
+        }
+        return mock;
+    }
+
+    @Test
+    public void testCompositeStructure() throws Exception {
+        final CompositeReaderRegistryBuilder compositeReaderRegistryBuilder = new CompositeReaderRegistryBuilder();
+        /*
+            Composite reader structure ordered left from right
+
+            1,      2,      3,      4
+                            31      42, 41
+                                        411
+         */
+        compositeReaderRegistryBuilder.add(reader1);
+        compositeReaderRegistryBuilder.addAfter(reader2, reader1.getManagedDataObjectType());
+        compositeReaderRegistryBuilder.addAfter(reader3, reader2.getManagedDataObjectType());
+        compositeReaderRegistryBuilder.addAfter(reader31, reader1.getManagedDataObjectType());
+        compositeReaderRegistryBuilder.addAfter(reader4, reader3.getManagedDataObjectType());
+        compositeReaderRegistryBuilder.add(reader41);
+        compositeReaderRegistryBuilder.addBefore(reader42, reader41.getManagedDataObjectType());
+        compositeReaderRegistryBuilder.add(reader411);
+
+        final ReaderRegistry build = compositeReaderRegistryBuilder.build();
+
+        final Map<Class<? extends DataObject>, Reader<? extends DataObject, ? extends Builder<?>>> rootReaders =
+                ((CompositeReaderRegistry) build).getRootReaders();
+        final List<Class<? extends DataObject>> rootReaderOrder = Lists.newArrayList(rootReaders.keySet());
+
+        assertEquals(reader1.getManagedDataObjectType().getTargetType(), rootReaderOrder.get(0));
+        assertEquals(reader2.getManagedDataObjectType().getTargetType(), rootReaderOrder.get(1));
+        assertEquals(reader3.getManagedDataObjectType().getTargetType(), rootReaderOrder.get(2));
+        assertEquals(reader4.getManagedDataObjectType().getTargetType(), rootReaderOrder.get(3));
+
+        assertFalse(rootReaders.get(DataObjects.DataObject1.class) instanceof CompositeReader);
+        assertFalse(rootReaders.get(DataObjects.DataObject2.class) instanceof CompositeReader);
+        assertTrue(rootReaders.get(DataObjects.DataObject3.class) instanceof CompositeReader);
+        assertTrue(rootReaders.get(DataObjects.DataObject4.class) instanceof CompositeReader);
+
+        final ImmutableMap<Class<?>, Reader<? extends DataObject, ? extends Builder<?>>> childReaders =
+                ((CompositeReader<? extends DataObject, ? extends Builder<?>>) rootReaders
+                        .get(DataObjects.DataObject4.class)).getChildReaders();
+        final List<Class<?>> orderedChildReaders = Lists.newArrayList(childReaders.keySet());
+
+        assertEquals(reader42.getManagedDataObjectType().getTargetType(), orderedChildReaders.get(0));
+        assertEquals(reader41.getManagedDataObjectType().getTargetType(), orderedChildReaders.get(1));
+        assertTrue(childReaders.get(DataObjects.DataObject4.DataObject41.class) instanceof CompositeReader);
+        assertFalse(childReaders.get(DataObjects.DataObject4.DataObject42.class) instanceof CompositeReader);
+    }
+}
\ No newline at end of file
diff --git a/v3po/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/read/registry/SubtreeReaderTest.java b/v3po/translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/util/read/registry/SubtreeReaderTest.java
new file mode 100644 (file)
index 0000000..324d71d
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.translate.util.read.registry;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
+import io.fd.honeycomb.v3po.translate.read.ReadContext;
+import io.fd.honeycomb.v3po.translate.read.Reader;
+import io.fd.honeycomb.v3po.translate.util.DataObjects;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.ChildOf;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class SubtreeReaderTest {
+
+    @Mock
+    private Reader<DataObjects.DataObject4, Builder<DataObjects.DataObject4>> delegate;
+    @Mock
+    private Reader<DataObject1, Builder<DataObject1>> delegateLocal;
+    @Mock
+    private ReadContext ctx;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        doReturn(DataObjects.DataObject4.IID).when(delegate).getManagedDataObjectType();
+        doReturn(DataObject1.IID).when(delegateLocal).getManagedDataObjectType();
+    }
+
+    @Test
+    public void testCreate() throws Exception {
+        final Reader<DataObjects.DataObject4, Builder<DataObjects.DataObject4>> subtreeR =
+                SubtreeReader.createForReader(Sets.newHashSet(DataObjects.DataObject4.DataObject41.IID), delegate);
+
+        subtreeR.getBuilder(DataObjects.DataObject4.IID);
+        verify(delegate).getBuilder(DataObjects.DataObject4.IID);
+
+        subtreeR.getManagedDataObjectType();
+        verify(delegate, atLeastOnce()).getManagedDataObjectType();
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testCreateInvalid() throws Exception {
+        SubtreeReader.createForReader(Sets.newHashSet(DataObjects.DataObject1.IID), delegate);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testReadOnlySubtreeCannotFilter() throws Exception {
+        final Reader<DataObjects.DataObject4, Builder<DataObjects.DataObject4>> subtreeR =
+                SubtreeReader.createForReader(Sets.newHashSet(DataObjects.DataObject4.DataObject41.IID), delegate);
+
+        doReturn(Optional.fromNullable(mock(DataObjects.DataObject4.class))).when(delegate).read(DataObjects.DataObject4.IID, ctx);
+        subtreeR.read(DataObjects.DataObject4.DataObject41.IID, ctx);
+    }
+
+    @Test
+    public void testReadOnlySubtreeNotPresent() throws Exception {
+        final Reader<DataObjects.DataObject4, Builder<DataObjects.DataObject4>> subtreeR =
+                SubtreeReader.createForReader(Sets.newHashSet(DataObjects.DataObject4.DataObject41.IID), delegate);
+
+        doReturn(Optional.absent()).when(delegate).read(DataObjects.DataObject4.IID, ctx);
+        assertFalse(subtreeR.read(DataObjects.DataObject4.DataObject41.IID, ctx).isPresent());
+    }
+
+    @Test
+    public void testReadOnlySubtreeChild() throws Exception {
+        final Reader<DataObject1, Builder<DataObject1>> subtreeR =
+                SubtreeReader.createForReader(Sets.newHashSet(DataObject1.DataObject11.IID), delegateLocal);
+
+        final DataObject1 mock = mock(DataObject1.class);
+        final DataObject1.DataObject11 mock11 = mock(DataObject1.DataObject11.class);
+        doReturn(mock11).when(mock).getDataObject11();
+        doReturn(Optional.fromNullable(mock)).when(delegateLocal).read(DataObject1.IID, ctx);
+        assertEquals(mock11, subtreeR.read(DataObject1.DataObject11.IID, ctx).get());
+    }
+
+    @Test
+    public void testReadEntireSubtree() throws Exception {
+        final Reader<DataObject1, Builder<DataObject1>> subtreeR =
+                SubtreeReader.createForReader(Sets.newHashSet(DataObject1.DataObject11.IID), delegateLocal);
+
+        final DataObject1 mock = mock(DataObject1.class);
+        final DataObject1.DataObject11 mock11 = mock(DataObject1.DataObject11.class);
+        doReturn(mock11).when(mock).getDataObject11();
+        doReturn(Optional.fromNullable(mock)).when(delegateLocal).read(DataObject1.IID, ctx);
+        assertEquals(mock, subtreeR.read(DataObject1.IID, ctx).get());
+    }
+
+    public abstract static class DataObject1 implements DataObject {
+        public static InstanceIdentifier<DataObject1> IID = InstanceIdentifier.create(DataObject1.class);
+
+        public abstract DataObject11 getDataObject11();
+
+        public abstract static class DataObject11 implements DataObject, ChildOf<DataObject1> {
+            public static InstanceIdentifier<DataObject11> IID = DataObject1.IID.child(DataObject11.class);
+        }
+    }
+}
index 92449af..7a664ee 100644 (file)
@@ -24,65 +24,46 @@ import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 
 import com.google.common.collect.Sets;
+import io.fd.honeycomb.v3po.translate.util.DataObjects.DataObject1;
+import io.fd.honeycomb.v3po.translate.util.DataObjects.DataObject3;
+import io.fd.honeycomb.v3po.translate.util.DataObjects.DataObject4;
 import org.junit.Test;
-import org.opendaylight.yangtools.yang.binding.ChildOf;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
 public class TypeHierarchyTest {
 
     @Test
     public void testHierarchy() throws Exception {
         final TypeHierarchy typeHierarchy = TypeHierarchy.create(Sets.newHashSet(
-                DataObject3.DataObject31.DataObject311.IID,
-                DataObject3.DataObject31.IID,/* Included in previous already */
+                DataObject4.DataObject41.DataObject411.IID,
+                DataObject4.DataObject41.IID,/* Included in previous already */
                 DataObject1.IID,
-                DataObject2.DataObject21.IID));
+                DataObject3.DataObject31.IID));
 
         // Roots
         assertThat(typeHierarchy.getRoots().size(), is(3));
-        assertThat(typeHierarchy.getRoots(), hasItems(DataObject1.IID, DataObject2.IID, DataObject3.IID));
+        assertThat(typeHierarchy.getRoots(), hasItems(DataObject1.IID, DataObject3.IID, DataObject4.IID));
 
         // Leaves
         assertThat(typeHierarchy.getDirectChildren(DataObject1.IID).size(), is(0));
-        assertThat(typeHierarchy.getDirectChildren(DataObject2.DataObject21.IID).size(), is(0));
-        assertThat(typeHierarchy.getDirectChildren(DataObject3.DataObject31.DataObject311.IID).size(), is(0));
+        assertThat(typeHierarchy.getDirectChildren(DataObject3.DataObject31.IID).size(), is(0));
+        assertThat(typeHierarchy.getDirectChildren(DataObject4.DataObject41.DataObject411.IID).size(), is(0));
 
         // Intermediate leaves
-        assertThat(typeHierarchy.getDirectChildren(DataObject2.IID).size(), is(1));
-        assertThat(typeHierarchy.getDirectChildren(DataObject2.IID), hasItem(DataObject2.DataObject21.IID));
-        assertEquals(typeHierarchy.getDirectChildren(DataObject2.IID), typeHierarchy.getAllChildren(DataObject2.IID));
-
-        assertThat(typeHierarchy.getDirectChildren(DataObject3.DataObject31.IID).size(), is(1));
-        assertThat(typeHierarchy.getDirectChildren(DataObject3.DataObject31.IID), hasItem(
-                DataObject3.DataObject31.DataObject311.IID));
-        assertEquals(typeHierarchy.getDirectChildren(DataObject3.DataObject31.IID), typeHierarchy.getAllChildren(
-                DataObject3.DataObject31.IID));
-
         assertThat(typeHierarchy.getDirectChildren(DataObject3.IID).size(), is(1));
         assertThat(typeHierarchy.getDirectChildren(DataObject3.IID), hasItem(DataObject3.DataObject31.IID));
-        assertThat(typeHierarchy.getAllChildren(DataObject3.IID).size(), is(2));
-        assertTrue(typeHierarchy.getAllChildren(DataObject3.IID).contains(DataObject3.DataObject31.IID));
-        assertTrue(typeHierarchy.getAllChildren(DataObject3.IID).contains(DataObject3.DataObject31.DataObject311.IID));
-    }
+        assertEquals(typeHierarchy.getDirectChildren(DataObject3.IID), typeHierarchy.getAllChildren(DataObject3.IID));
 
-    private abstract static class DataObject1 implements DataObject {
-        static InstanceIdentifier<DataObject1> IID = InstanceIdentifier.create(DataObject1.class);
-    }
-    private abstract static class DataObject2 implements DataObject {
-        static InstanceIdentifier<DataObject2> IID = InstanceIdentifier.create(DataObject2.class);
-        private abstract static class DataObject21 implements DataObject, ChildOf<DataObject2> {
-            static InstanceIdentifier<DataObject21> IID = DataObject2.IID.child(DataObject21.class);
-        }
-    }
-    private abstract static class DataObject3 implements DataObject {
-        static InstanceIdentifier<DataObject3> IID = InstanceIdentifier.create(DataObject3.class);
-        private abstract static class DataObject31 implements DataObject, ChildOf<DataObject3> {
-            static InstanceIdentifier<DataObject31> IID = DataObject3.IID.child(DataObject31.class);
-            private abstract static class DataObject311 implements DataObject, ChildOf<DataObject31> {
-                static InstanceIdentifier<DataObject311> IID = DataObject31.IID.child(DataObject311.class);
-            }
-        }
+        assertThat(typeHierarchy.getDirectChildren(DataObject4.DataObject41.IID).size(), is(1));
+        assertThat(typeHierarchy.getDirectChildren(DataObject4.DataObject41.IID), hasItem(
+                DataObject4.DataObject41.DataObject411.IID));
+        assertEquals(typeHierarchy.getDirectChildren(DataObject4.DataObject41.IID), typeHierarchy.getAllChildren(
+                DataObject4.DataObject41.IID));
+
+        assertThat(typeHierarchy.getDirectChildren(DataObject4.IID).size(), is(1));
+        assertThat(typeHierarchy.getDirectChildren(DataObject4.IID), hasItem(DataObject4.DataObject41.IID));
+        assertThat(typeHierarchy.getAllChildren(DataObject4.IID).size(), is(2));
+        assertTrue(typeHierarchy.getAllChildren(DataObject4.IID).contains(DataObject4.DataObject41.IID));
+        assertTrue(typeHierarchy.getAllChildren(DataObject4.IID).contains(DataObject4.DataObject41.DataObject411.IID));
     }
 }
 
index da7ac09..743d84c 100644 (file)
@@ -13,11 +13,11 @@ import static org.mockito.Mockito.when;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
+import io.fd.honeycomb.v3po.translate.util.DataObjects;
 import io.fd.honeycomb.v3po.translate.write.Writer;
 import java.util.ArrayList;
 import java.util.List;
 import org.junit.Test;
-import org.opendaylight.yangtools.yang.binding.ChildOf;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
@@ -31,19 +31,19 @@ public class FlatWriterRegistryBuilderTest {
             1   ->  2   ->  3
                         ->  4
          */
-        flatWriterRegistryBuilder.add(mockWriter(DataObject3.class));
-        flatWriterRegistryBuilder.add(mockWriter(DataObject4.class));
-        flatWriterRegistryBuilder.addBefore(mockWriter(DataObject2.class),
-                Lists.newArrayList(DataObject3.IID, DataObject4.IID));
-        flatWriterRegistryBuilder.addBefore(mockWriter(DataObject1.class), DataObject2.IID);
+        flatWriterRegistryBuilder.add(mockWriter(DataObjects.DataObject3.class));
+        flatWriterRegistryBuilder.add(mockWriter(DataObjects.DataObject4.class));
+        flatWriterRegistryBuilder.addBefore(mockWriter(DataObjects.DataObject2.class),
+                Lists.newArrayList(DataObjects.DataObject3.IID, DataObjects.DataObject4.IID));
+        flatWriterRegistryBuilder.addBefore(mockWriter(DataObjects.DataObject1.class), DataObjects.DataObject2.IID);
         final ImmutableMap<InstanceIdentifier<?>, Writer<?>> mappedWriters =
                 flatWriterRegistryBuilder.getMappedHandlers();
 
         final ArrayList<InstanceIdentifier<?>> typesInList = Lists.newArrayList(mappedWriters.keySet());
-        assertEquals(DataObject1.IID, typesInList.get(0));
-        assertEquals(DataObject2.IID, typesInList.get(1));
-        assertThat(typesInList.get(2), anyOf(equalTo(DataObject3.IID), equalTo(DataObject4.IID)));
-        assertThat(typesInList.get(3), anyOf(equalTo(DataObject3.IID), equalTo(DataObject4.IID)));
+        assertEquals(DataObjects.DataObject1.IID, typesInList.get(0));
+        assertEquals(DataObjects.DataObject2.IID, typesInList.get(1));
+        assertThat(typesInList.get(2), anyOf(equalTo(DataObjects.DataObject3.IID), equalTo(DataObjects.DataObject4.IID)));
+        assertThat(typesInList.get(3), anyOf(equalTo(DataObjects.DataObject3.IID), equalTo(DataObjects.DataObject4.IID)));
     }
 
     @Test
@@ -53,18 +53,18 @@ public class FlatWriterRegistryBuilderTest {
             1   ->  2   ->  3
                         ->  4
          */
-        flatWriterRegistryBuilder.add(mockWriter(DataObject1.class));
-        flatWriterRegistryBuilder.addAfter(mockWriter(DataObject2.class), DataObject1.IID);
-        flatWriterRegistryBuilder.addAfter(mockWriter(DataObject3.class), DataObject2.IID);
-        flatWriterRegistryBuilder.addAfter(mockWriter(DataObject4.class), DataObject2.IID);
+        flatWriterRegistryBuilder.add(mockWriter(DataObjects.DataObject1.class));
+        flatWriterRegistryBuilder.addAfter(mockWriter(DataObjects.DataObject2.class), DataObjects.DataObject1.IID);
+        flatWriterRegistryBuilder.addAfter(mockWriter(DataObjects.DataObject3.class), DataObjects.DataObject2.IID);
+        flatWriterRegistryBuilder.addAfter(mockWriter(DataObjects.DataObject4.class), DataObjects.DataObject2.IID);
         final ImmutableMap<InstanceIdentifier<?>, Writer<?>> mappedWriters =
                 flatWriterRegistryBuilder.getMappedHandlers();
 
         final List<InstanceIdentifier<?>> typesInList = Lists.newArrayList(mappedWriters.keySet());
-        assertEquals(DataObject1.IID, typesInList.get(0));
-        assertEquals(DataObject2.IID, typesInList.get(1));
-        assertThat(typesInList.get(2), anyOf(equalTo(DataObject3.IID), equalTo(DataObject4.IID)));
-        assertThat(typesInList.get(3), anyOf(equalTo(DataObject3.IID), equalTo(DataObject4.IID)));
+        assertEquals(DataObjects.DataObject1.IID, typesInList.get(0));
+        assertEquals(DataObjects.DataObject2.IID, typesInList.get(1));
+        assertThat(typesInList.get(2), anyOf(equalTo(DataObjects.DataObject3.IID), equalTo(DataObjects.DataObject4.IID)));
+        assertThat(typesInList.get(3), anyOf(equalTo(DataObjects.DataObject3.IID), equalTo(DataObjects.DataObject4.IID)));
     }
 
     @Test(expected = IllegalArgumentException.class)
@@ -73,51 +73,51 @@ public class FlatWriterRegistryBuilderTest {
         /*
             1   ->  2   ->  1
          */
-        flatWriterRegistryBuilder.add(mockWriter(DataObject1.class));
-        flatWriterRegistryBuilder.addAfter(mockWriter(DataObject2.class), DataObject1.IID);
-        flatWriterRegistryBuilder.addAfter(mockWriter(DataObject1.class), DataObject2.IID);
+        flatWriterRegistryBuilder.add(mockWriter(DataObjects.DataObject1.class));
+        flatWriterRegistryBuilder.addAfter(mockWriter(DataObjects.DataObject2.class), DataObjects.DataObject1.IID);
+        flatWriterRegistryBuilder.addAfter(mockWriter(DataObjects.DataObject1.class), DataObjects.DataObject2.IID);
     }
 
     @Test(expected = IllegalArgumentException.class)
     public void testAddWriterTwice() throws Exception {
         final FlatWriterRegistryBuilder flatWriterRegistryBuilder = new FlatWriterRegistryBuilder();
-        flatWriterRegistryBuilder.add(mockWriter(DataObject1.class));
-        flatWriterRegistryBuilder.add(mockWriter(DataObject1.class));
+        flatWriterRegistryBuilder.add(mockWriter(DataObjects.DataObject1.class));
+        flatWriterRegistryBuilder.add(mockWriter(DataObjects.DataObject1.class));
     }
 
     @Test
     public void testAddSubtreeWriter() throws Exception {
         final FlatWriterRegistryBuilder flatWriterRegistryBuilder = new FlatWriterRegistryBuilder();
         flatWriterRegistryBuilder.subtreeAdd(
-                Sets.newHashSet(DataObject4.DataObject5.IID,
-                                DataObject4.DataObject5.IID),
-                mockWriter(DataObject4.class));
+                Sets.newHashSet(DataObjects.DataObject4.DataObject41.IID,
+                                DataObjects.DataObject4.DataObject41.IID),
+                mockWriter(DataObjects.DataObject4.class));
         final ImmutableMap<InstanceIdentifier<?>, Writer<?>> mappedWriters =
                 flatWriterRegistryBuilder.getMappedHandlers();
         final ArrayList<InstanceIdentifier<?>> typesInList = Lists.newArrayList(mappedWriters.keySet());
 
-        assertEquals(DataObject4.IID, typesInList.get(0));
+        assertEquals(DataObjects.DataObject4.IID, typesInList.get(0));
         assertEquals(1, typesInList.size());
     }
 
     @Test
     public void testCreateSubtreeWriter() throws Exception {
         final Writer<?> forWriter = SubtreeWriter.createForWriter(Sets.newHashSet(
-                DataObject4.DataObject5.IID,
-                DataObject4.DataObject5.DataObject51.IID,
-                DataObject4.DataObject6.IID),
-                mockWriter(DataObject4.class));
+                DataObjects.DataObject4.DataObject41.IID,
+                DataObjects.DataObject4.DataObject41.DataObject411.IID,
+                DataObjects.DataObject4.DataObject42.IID),
+                mockWriter(DataObjects.DataObject4.class));
         assertThat(forWriter, instanceOf(SubtreeWriter.class));
         assertThat(((SubtreeWriter<?>) forWriter).getHandledChildTypes().size(), is(3));
-        assertThat(((SubtreeWriter<?>) forWriter).getHandledChildTypes(), hasItems(DataObject4.DataObject5.IID,
-                DataObject4.DataObject6.IID, DataObject4.DataObject5.DataObject51.IID));
+        assertThat(((SubtreeWriter<?>) forWriter).getHandledChildTypes(), hasItems(DataObjects.DataObject4.DataObject41.IID,
+                DataObjects.DataObject4.DataObject42.IID, DataObjects.DataObject4.DataObject41.DataObject411.IID));
     }
 
     @Test(expected = IllegalArgumentException.class)
     public void testCreateInvalidSubtreeWriter() throws Exception {
         SubtreeWriter.createForWriter(Sets.newHashSet(
-                InstanceIdentifier.create(DataObject3.class).child(DataObject3.DataObject31.class)),
-                mockWriter(DataObject4.class));
+                InstanceIdentifier.create(DataObjects.DataObject3.class).child(DataObjects.DataObject3.DataObject31.class)),
+                mockWriter(DataObjects.DataObject4.class));
     }
 
     @SuppressWarnings("unchecked")
@@ -128,29 +128,4 @@ public class FlatWriterRegistryBuilderTest {
         return mock;
     }
 
-    private abstract static class DataObject1 implements DataObject {
-        static InstanceIdentifier<DataObject1> IID = InstanceIdentifier.create(DataObject1.class);
-    }
-    private abstract static class DataObject2 implements DataObject {
-        static InstanceIdentifier<DataObject2> IID = InstanceIdentifier.create(DataObject2.class);
-    }
-    private abstract static class DataObject3 implements DataObject {
-        static InstanceIdentifier<DataObject3> IID = InstanceIdentifier.create(DataObject3.class);
-        private abstract static class DataObject31 implements DataObject, ChildOf<DataObject3> {
-            static InstanceIdentifier<DataObject31> IID = DataObject3.IID.child(DataObject31.class);
-        }
-    }
-    private abstract static class DataObject4 implements DataObject {
-        static InstanceIdentifier<DataObject4> IID = InstanceIdentifier.create(DataObject4.class);
-        private abstract static class DataObject5 implements DataObject, ChildOf<DataObject4> {
-            static InstanceIdentifier<DataObject5> IID = DataObject4.IID.child(DataObject5.class);
-            private abstract static class DataObject51 implements DataObject, ChildOf<DataObject5> {
-                static InstanceIdentifier<DataObject51> IID = DataObject5.IID.child(DataObject51.class);
-            }
-        }
-        private abstract static class DataObject6 implements DataObject, ChildOf<DataObject4> {
-            static InstanceIdentifier<DataObject6> IID = DataObject4.IID.child(DataObject6.class);
-        }
-    }
-
 }
\ No newline at end of file
index 1b4a059..a72cb4f 100644 (file)
@@ -17,6 +17,9 @@ import com.google.common.collect.HashMultimap;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableMultimap;
 import com.google.common.collect.Multimap;
+import io.fd.honeycomb.v3po.translate.util.DataObjects.DataObject1;
+import io.fd.honeycomb.v3po.translate.util.DataObjects.DataObject2;
+import io.fd.honeycomb.v3po.translate.util.DataObjects.DataObject3;
 import io.fd.honeycomb.v3po.translate.write.DataObjectUpdate;
 import io.fd.honeycomb.v3po.translate.write.WriteContext;
 import io.fd.honeycomb.v3po.translate.write.Writer;
@@ -258,14 +261,4 @@ public class FlatWriterRegistryTest {
         final InstanceIdentifier<D> iid = (InstanceIdentifier<D>) type.getDeclaredField("IID").get(null);
         updates.put(iid, DataObjectUpdate.create(iid, mock(type), mock(type)));
     }
-
-    private abstract static class DataObject1 implements DataObject {
-        static final InstanceIdentifier<DataObject1> IID = InstanceIdentifier.create(DataObject1.class);
-    }
-    private abstract static class DataObject2 implements DataObject {
-        static final InstanceIdentifier<DataObject2> IID = InstanceIdentifier.create(DataObject2.class);
-    }
-    private abstract static class DataObject3 implements DataObject {
-        static final InstanceIdentifier<DataObject3> IID = InstanceIdentifier.create(DataObject3.class);
-    }
 }
\ No newline at end of file
index b7dcadc..627c69c 100644 (file)
@@ -22,28 +22,28 @@ import static org.junit.Assert.assertThat;
 import static org.mockito.Mockito.when;
 
 import com.google.common.collect.Sets;
+import io.fd.honeycomb.v3po.translate.util.DataObjects;
 import io.fd.honeycomb.v3po.translate.write.Writer;
 import java.util.Collections;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-import org.opendaylight.yangtools.yang.binding.ChildOf;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
 public class SubtreeWriterTest {
 
     @Mock
-    Writer<DataObject1> writer;
+    Writer<DataObjects.DataObject4> writer;
     @Mock
-    Writer<DataObject1.DataObject11> writer11;
+    Writer<DataObjects.DataObject4.DataObject41> writer11;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        when(writer.getManagedDataObjectType()).thenReturn(DataObject1.IID);
-        when(writer11.getManagedDataObjectType()).thenReturn(DataObject1.DataObject11.IID);
+        when(writer.getManagedDataObjectType()).thenReturn(DataObjects.DataObject4.IID);
+        when(writer11.getManagedDataObjectType()).thenReturn(DataObjects.DataObject4.DataObject41.IID);
     }
 
     @Test(expected = IllegalArgumentException.class)
@@ -55,15 +55,15 @@ public class SubtreeWriterTest {
     @Test(expected = IllegalArgumentException.class)
     public void testSubtreeWriterCreationFailInvalidIid() throws Exception {
         // The subtree node identified by IID.c(DataObject.class) is not a child of writer.getManagedDataObjectType
-        SubtreeWriter.createForWriter(Collections.singleton(DataObject1.IID), writer);
+        SubtreeWriter.createForWriter(Collections.singleton(DataObjects.DataObject4.IID), writer);
     }
 
     @Test
     public void testSubtreeWriterCreation() throws Exception {
         final SubtreeWriter<?> forWriter = (SubtreeWriter<?>) SubtreeWriter.createForWriter(Sets.newHashSet(
-                DataObject1.DataObject11.IID,
-                DataObject1.DataObject11.DataObject111.IID,
-                DataObject1.DataObject12.IID),
+                DataObjects.DataObject4.DataObject41.IID,
+                DataObjects.DataObject4.DataObject41.DataObject411.IID,
+                DataObjects.DataObject4.DataObject42.IID),
                 writer);
 
         assertEquals(writer.getManagedDataObjectType(), forWriter.getManagedDataObjectType());
@@ -73,24 +73,12 @@ public class SubtreeWriterTest {
     @Test
     public void testSubtreeWriterHandledTypes() throws Exception {
         final SubtreeWriter<?> forWriter = (SubtreeWriter<?>) SubtreeWriter.createForWriter(Sets.newHashSet(
-                DataObject1.DataObject11.DataObject111.IID),
+                DataObjects.DataObject4.DataObject41.DataObject411.IID),
                 writer);
 
         assertEquals(writer.getManagedDataObjectType(), forWriter.getManagedDataObjectType());
         assertEquals(1, forWriter.getHandledChildTypes().size());
-        assertThat(forWriter.getHandledChildTypes(), hasItem(DataObject1.DataObject11.DataObject111.IID));
+        assertThat(forWriter.getHandledChildTypes(), hasItem(DataObjects.DataObject4.DataObject41.DataObject411.IID));
     }
 
-    private abstract static class DataObject1 implements DataObject {
-        static InstanceIdentifier<DataObject1> IID = InstanceIdentifier.create(DataObject1.class);
-        private abstract static class DataObject11 implements DataObject, ChildOf<DataObject1> {
-            static InstanceIdentifier<DataObject11> IID = DataObject1.IID.child(DataObject11.class);
-            private abstract static class DataObject111 implements DataObject, ChildOf<DataObject11> {
-                static InstanceIdentifier<DataObject111> IID = DataObject11.IID.child(DataObject111.class);
-            }
-        }
-        private abstract static class DataObject12 implements DataObject, ChildOf<DataObject1> {
-            static InstanceIdentifier<DataObject12> IID = DataObject1.IID.child(DataObject12.class);
-        }
-    }
 }
\ No newline at end of file
index 635c77a..7ac666b 100644 (file)
@@ -100,11 +100,6 @@ public class InterfacesHoneycombWriterModule extends
             this.classifyTableContext = classifyTableContextDependency;
         }
 
-        @Override
-        public void close() throws Exception {
-            // unregister is not supported in ModifiableWriterRegistry (not really needed though)
-        }
-
         @Override
         public void init(final ModifiableWriterRegistryBuilder registry) {
             // Interfaces
index 83758d8..fb2f281 100644 (file)
@@ -150,10 +150,5 @@ public class InterfacesStateHoneycombReaderModule extends
                     new GenericReader<>(vppIfcAugId.child(Acl.class), new AclCustomizer(jvpp, ifcCtx, classifyCtx)));
 
         }
-
-        @Override
-        public void close() throws Exception {
-            // unregister not supported
-        }
     }
 }
index ca05b39..5d15d16 100644 (file)
@@ -60,11 +60,6 @@ public class VppClassifierHoneycombWriterModule extends
             this.classifyTableContext = classifyTableContext;
         }
 
-        @Override
-        public void close() throws Exception {
-            // unregister is not supported in ModifiableWriterRegistry (not really needed though)
-        }
-
         @Override
         public void init(final ModifiableWriterRegistryBuilder registry) {
 
index 4a91f26..80370fe 100644 (file)
@@ -55,10 +55,5 @@ public class VppClassifierStateHoneycombReaderModule extends org.opendaylight.ya
             final InstanceIdentifier<ClassifySession> classSesId = classTblId.child(ClassifySession.class);
             registry.add(new GenericListReader<>(classSesId, new ClassifySessionReader(jvpp, classifyCtx)));
         }
-
-        @Override
-        public void close() throws Exception {
-            // Noop, no unregister provided
-        }
     }
 }
index ba42cfb..4b31e2e 100644 (file)
@@ -56,11 +56,6 @@ public class VppHoneycombWriterModule extends
             this.ifcContext = interfaceContextVppDependency;
         }
 
-        @Override
-        public void close() throws Exception {
-            // unregister is not supported in ModifiableWriterRegistry (not really needed though)
-        }
-
         @Override
         public void init(final ModifiableWriterRegistryBuilder registry) {
             // Vpp has no handlers
index 4634a5b..98d38c5 100644 (file)
@@ -134,11 +134,6 @@ public class VppStateHoneycombReaderModule extends
             this.keepaliveExecutor = keepaliveExecutorDependency;
         }
 
-        @Override
-        public void close() throws Exception {
-            // TODO unregister not available
-        }
-
         @Override
         public void init(final ModifiableReaderRegistryBuilder registry) {
             // VppState(Structural)