HONEYCOMB-9: Simplify reader APIs, remove list of DataObjects
authorMaros Marsalek <[email protected]>
Tue, 12 Apr 2016 08:12:58 +0000 (10:12 +0200)
committerMaros Marsalek <[email protected]>
Tue, 12 Apr 2016 08:12:58 +0000 (10:12 +0200)
Change-Id: I0cb3f20ef4595b0143dcc7e0ad5475f121a9cc86
Signed-off-by: Maros Marsalek <[email protected]>
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppOperationalDataTree.java
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppReaderRegistry.java
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/ListVppReader.java [new file with mode: 0644]
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/VppReader.java
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/AbstractCompositeVppReader.java
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/CompositeChildVppReader.java
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/impl/CompositeListVppReader.java
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/util/DelegatingReaderRegistry.java
v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppOperationalDataTreeTest.java
v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vppstate/VppStateTest.java
v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vppstate/VppStateUtils.java

index c378365..3fddd10 100644 (file)
@@ -28,7 +28,6 @@ import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.Futures;
 import io.fd.honeycomb.v3po.impl.trans.r.ReaderRegistry;
 import java.util.Collection;
-import java.util.List;
 import java.util.Map;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -90,21 +89,17 @@ public final class VppOperationalDataTree implements ReadableVppDataTree {
 
         LOG.debug("VppOperationalDataProxy.read(), yangInstanceIdentifier={}", yangInstanceIdentifier);
         final InstanceIdentifier<?> path = serializer.fromYangInstanceIdentifier(yangInstanceIdentifier);
-        if (path == null) {
-            // TODO try to translate wildcarded identifiers here as a workaround if it is expected to be used that way
-            // Currently its not possible to read list using wildcarded ID. SO we may not need this at all.
-        }
         checkNotNull(path, "Invalid instance identifier %s. Cannot create BA equivalent.", yangInstanceIdentifier);
         LOG.debug("VppOperationalDataProxy.read(), path={}", path);
 
-        final List<? extends DataObject> dataObjects = readerRegistry.read(path);
+        final Optional<? extends DataObject> dataObject = readerRegistry.read(path);
 
-        if (dataObjects.isEmpty()) {
-            return Futures.immediateCheckedFuture(Optional.<NormalizedNode<?, ?>>absent());
+        if (dataObject.isPresent()) {
+            final NormalizedNode<?, ?> value = toNormalizedNodeFunction(path).apply(dataObject.get());
+            return Futures.immediateCheckedFuture(Optional.<NormalizedNode<?, ?>>fromNullable(value));
         }
 
-        final NormalizedNode<?, ?> value = wrapDataObjects(yangInstanceIdentifier, path, dataObjects);
-        return Futures.immediateCheckedFuture(Optional.<NormalizedNode<?, ?>>fromNullable(value));
+        return Futures.immediateCheckedFuture(Optional.<NormalizedNode<?, ?>>absent());
     }
 
     private DataSchemaNode getSchemaNode(final @Nonnull YangInstanceIdentifier yangInstanceIdentifier) {
@@ -175,7 +170,7 @@ public final class VppOperationalDataTree implements ReadableVppDataTree {
             public NormalizedNode<?, ?> apply(@Nullable final DataObject dataObject) {
                 LOG.trace("VppOperationalDataProxy.toNormalizedNode(), path={}, dataObject={}", path, dataObject);
                 final Map.Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> entry =
-                        serializer.toNormalizedNode(path, dataObject);
+                    serializer.toNormalizedNode(path, dataObject);
 
                 LOG.trace("VppOperationalDataProxy.toNormalizedNode(), normalizedNodeEntry={}", entry);
                 return entry.getValue();
index c5d4a81..df7b656 100644 (file)
@@ -16,6 +16,7 @@
 
 package io.fd.honeycomb.v3po.impl.data;
 
+import com.google.common.base.Optional;
 import com.google.common.collect.Multimap;
 import io.fd.honeycomb.v3po.impl.trans.r.ChildVppReader;
 import io.fd.honeycomb.v3po.impl.trans.r.ReaderRegistry;
@@ -100,7 +101,7 @@ public class VppReaderRegistry implements ReaderRegistry {
 
     @Nonnull
     @Override
-    public List<? extends DataObject> read(@Nonnull final InstanceIdentifier<? extends DataObject> id) {
+    public Optional<? extends DataObject> read(@Nonnull final InstanceIdentifier<? extends DataObject> id) {
         return reader.read(id);
     }
 
diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/ListVppReader.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/r/ListVppReader.java
new file mode 100644 (file)
index 0000000..8a7f29c
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.impl.trans.r;
+
+import com.google.common.annotations.Beta;
+import java.util.List;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * List VPP reader, allowing read of all the elements
+ *
+ * @param <D> Specific DataObject derived type, that is handled by this reader
+ */
+@Beta
+public interface ListVppReader<D extends DataObject & Identifiable<K>, K extends Identifier<D>> extends VppReader<D> {
+
+    /**
+     * Read all elements in this list
+     *
+     * @param id Wildcarded identifier of list managed by this reader
+     *
+     * @return List of all entries in this list
+     */
+    @Nonnull
+    List<D> readList(@Nonnull final InstanceIdentifier<D> id);
+}
index 8af4938..1cc76a3 100644 (file)
@@ -17,8 +17,8 @@
 package io.fd.honeycomb.v3po.impl.trans.r;
 
 import com.google.common.annotations.Beta;
+import com.google.common.base.Optional;
 import io.fd.honeycomb.v3po.impl.trans.SubtreeManager;
-import java.util.List;
 import javax.annotation.Nonnull;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -44,6 +44,6 @@ public interface VppReader<D extends DataObject> extends SubtreeManager<D> {
      * @return List of DataObjects identified by id. If the ID points to a single node, it will be wrapped in a list
      */
     @Nonnull
-    List<? extends DataObject> read(@Nonnull final InstanceIdentifier<? extends DataObject> id);
+    Optional<? extends DataObject> read(@Nonnull final InstanceIdentifier<? extends DataObject> id);
 
 }
index 5111924..61f318b 100644 (file)
 
 package io.fd.honeycomb.v3po.impl.trans.r.impl;
 
+import static com.google.common.base.Preconditions.checkArgument;
+
 import com.google.common.annotations.Beta;
 import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.Lists;
+import com.google.common.collect.Iterables;
 import io.fd.honeycomb.v3po.impl.trans.r.ChildVppReader;
 import io.fd.honeycomb.v3po.impl.trans.r.VppReader;
 import io.fd.honeycomb.v3po.impl.trans.util.ReflectionUtils;
@@ -67,7 +68,7 @@ abstract class AbstractCompositeVppReader<D extends DataObject, B extends Builde
     /**
      * @param id {@link InstanceIdentifier} pointing to current node. In case of keyed list, key must be present.
      */
-    protected List<D> readCurrent(final InstanceIdentifier<D> id) {
+    protected Optional<D> readCurrent(final InstanceIdentifier<D> id) {
         LOG.debug("{}: Reading current: {}", this, id);
         final B builder = getBuilder(id);
         // Cache empty value to determine if anything has changed later TODO cache in a field
@@ -89,9 +90,9 @@ abstract class AbstractCompositeVppReader<D extends DataObject, B extends Builde
 
         // Need to check whether anything was filled in to determine if data is present or not.
         final D built = builder.build();
-        final List<D> read = built.equals(emptyValue)
-            ? Collections.<D>emptyList()
-            : Collections.singletonList(built);
+        final Optional<D> read = built.equals(emptyValue)
+            ? Optional.<D>absent()
+            : Optional.of(built);
 
         LOG.debug("{}: Current node read successfully. Result: {}", this, read);
         return read;
@@ -100,7 +101,7 @@ abstract class AbstractCompositeVppReader<D extends DataObject, B extends Builde
     @Nonnull
     @Override
     @SuppressWarnings("unchecked")
-    public List<? extends DataObject> read(@Nonnull final InstanceIdentifier<? extends DataObject> id) {
+    public Optional<? extends DataObject> read(@Nonnull final InstanceIdentifier<? extends DataObject> id) {
         LOG.trace("{}: Reading : {}", this, id);
         if (id.getTargetType().equals(getManagedDataObjectType().getTargetType())) {
             return readCurrent((InstanceIdentifier<D>) id);
@@ -109,7 +110,7 @@ abstract class AbstractCompositeVppReader<D extends DataObject, B extends Builde
         }
     }
 
-    private List<? extends DataObject> readSubtree(final InstanceIdentifier<? extends DataObject> id) {
+    private Optional<? extends DataObject> readSubtree(final InstanceIdentifier<? extends DataObject> id) {
         LOG.debug("{}: Reading subtree: {}", this, id);
         final Class<? extends DataObject> next = VppRWUtils.getNextId(id, getManagedDataObjectType()).getType();
         final ChildVppReader<? extends ChildOf<D>> vppReader = childReaders.get(next);
@@ -121,11 +122,11 @@ abstract class AbstractCompositeVppReader<D extends DataObject, B extends Builde
             LOG.debug("{}: Dedicated subtree reader missing for: {}. Reading current and filtering", this, next);
             // If there's no dedicated reader, use read current
             final InstanceIdentifier<D> currentId = VppRWUtils.cutId(id, getManagedDataObjectType());
-            final List<D> current = readCurrent(currentId);
+            final Optional<D> current = readCurrent(currentId);
             // then perform post-reading filtering (return only requested sub-node)
-            final List<? extends DataObject> readSubtree = current.isEmpty()
-                ? current
-                : filterSubtree(current, id, getManagedDataObjectType().getTargetType());
+            final Optional<? extends DataObject> readSubtree = current.isPresent()
+                ? filterSubtree(current.get(), id, getManagedDataObjectType().getTargetType())
+                : current;
 
             LOG.debug("{}: Subtree: {} read successfully. Result: {}", this, id, readSubtree);
             return readSubtree;
@@ -150,65 +151,59 @@ abstract class AbstractCompositeVppReader<D extends DataObject, B extends Builde
 
     // TODO move filtering out of here into a dedicated Filter ifc
     @Nonnull
-    private static List<? extends DataObject> filterSubtree(@Nonnull final List<? extends DataObject> built,
+    private static Optional<? extends DataObject> filterSubtree(@Nonnull final DataObject parent,
                                                             @Nonnull final InstanceIdentifier<? extends DataObject> absolutPath,
                                                             @Nonnull final Class<?> managedType) {
         // TODO is there a better way than reflection ? e.g. convert into NN and filter out with a utility
         // FIXME this needs to be recursive. right now it expects only 1 additional element in ID + test
 
-        List<DataObject> filtered = Lists.newArrayList();
-        for (DataObject parent : built) {
-            final InstanceIdentifier.PathArgument nextId =
-                VppRWUtils.getNextId(absolutPath, InstanceIdentifier.create(parent.getClass()));
+        final InstanceIdentifier.PathArgument nextId =
+            VppRWUtils.getNextId(absolutPath, InstanceIdentifier.create(parent.getClass()));
+
+        Optional<Method> method = ReflectionUtils.findMethodReflex(managedType, "get",
+            Collections.<Class<?>>emptyList(), nextId.getType());
 
-            Optional<Method> method = ReflectionUtils.findMethodReflex(managedType, "get",
-                Collections.<Class<?>>emptyList(), nextId.getType());
+        if (method.isPresent()) {
+            return Optional.fromNullable(filterSingle(parent, nextId, method.get()));
+        } else {
+            // List child nodes
+            method = ReflectionUtils.findMethodReflex(managedType,
+                "get" + nextId.getType().getSimpleName(), Collections.<Class<?>>emptyList(), List.class);
 
             if (method.isPresent()) {
-                filterSingle(filtered, parent, nextId, method);
+                return filterList(parent, nextId, method.get());
             } else {
-                // List child nodes
-                method = ReflectionUtils.findMethodReflex(managedType,
-                    "get" + nextId.getType().getSimpleName(), Collections.<Class<?>>emptyList(), List.class);
-
-                if (method.isPresent()) {
-                    filterList(filtered, parent, nextId, method);
-                } else {
-                    throw new IllegalStateException(
-                        "Unable to filter " + nextId + " from " + parent + " getters not found using reflexion");
-                }
+                throw new IllegalStateException(
+                    "Unable to filter " + nextId + " from " + parent + " getters not found using reflexion");
             }
         }
-
-        return filtered;
     }
 
     @SuppressWarnings("unchecked")
-    private static void filterList(final List<DataObject> filtered, final DataObject parent,
-                                   final InstanceIdentifier.PathArgument nextId, final Optional<Method> method) {
-        final List<? extends DataObject> invoke = (List<? extends DataObject>)invoke(method.get(), nextId, parent);
-
-        if (nextId instanceof InstanceIdentifier.IdentifiableItem<?, ?>) {
-            final Identifier key = ((InstanceIdentifier.IdentifiableItem) nextId).getKey();
-            filtered.addAll(Collections2.filter(invoke, new Predicate<DataObject>() {
-                @Override
-                public boolean apply(@Nullable final DataObject input) {
-                    final Optional<Method> keyGetter =
-                        ReflectionUtils.findMethodReflex(nextId.getType(), "get",
-                            Collections.<Class<?>>emptyList(), key.getClass());
-                    final Object actualKey;
-                    actualKey = invoke(keyGetter.get(), nextId, input);
-                    return key.equals(actualKey);
-                }
-            }));
-        } else {
-            filtered.addAll(invoke);
-        }
+    private static Optional<? extends DataObject> filterList(final DataObject parent,
+                                                             final InstanceIdentifier.PathArgument nextId,
+                                                             final Method method) {
+        final List<? extends DataObject> invoke = (List<? extends DataObject>) invoke(method, nextId, parent);
+
+        checkArgument(nextId instanceof InstanceIdentifier.IdentifiableItem<?, ?>,
+            "Unable to perform wildcarded read for %s", nextId);
+        final Identifier key = ((InstanceIdentifier.IdentifiableItem) nextId).getKey();
+        return Iterables.tryFind(invoke, new Predicate<DataObject>() {
+            @Override
+            public boolean apply(@Nullable final DataObject input) {
+                final Optional<Method> keyGetter =
+                    ReflectionUtils.findMethodReflex(nextId.getType(), "get",
+                        Collections.<Class<?>>emptyList(), key.getClass());
+                final Object actualKey;
+                actualKey = invoke(keyGetter.get(), nextId, input);
+                return key.equals(actualKey);
+            }
+        });
     }
 
-    private static void filterSingle(final List<DataObject> filtered, final DataObject parent,
-                                     final InstanceIdentifier.PathArgument nextId, final Optional<Method> method) {
-        filtered.add(nextId.getType().cast(invoke(method.get(), nextId, parent)));
+    private static DataObject filterSingle(final DataObject parent,
+                                           final InstanceIdentifier.PathArgument nextId, final Method method) {
+        return nextId.getType().cast(invoke(method, nextId, parent));
     }
 
     private static Object invoke(final Method method,
index 8f425b0..a64a72b 100644 (file)
@@ -79,8 +79,7 @@ public final class CompositeChildVppReader<C extends DataObject, B extends Build
     @Override
     public final void read(@Nonnull final InstanceIdentifier<? extends DataObject> parentId,
                            @Nonnull final Builder<? extends DataObject> parentBuilder) {
-        final Optional<C> read = Optional.fromNullable(readCurrent(VppRWUtils.appendTypeToId(parentId,
-            getManagedDataObjectType())).get(0));
+        final Optional<C> read = readCurrent(VppRWUtils.appendTypeToId(parentId, getManagedDataObjectType()));
 
         if(read.isPresent()) {
             customizer.merge(parentBuilder, read.get());
index 8d23aa4..7e3d845 100644 (file)
 package io.fd.honeycomb.v3po.impl.trans.r.impl;
 
 import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkState;
 
 import com.google.common.annotations.Beta;
+import com.google.common.base.Optional;
 import io.fd.honeycomb.v3po.impl.trans.r.ChildVppReader;
+import io.fd.honeycomb.v3po.impl.trans.r.ListVppReader;
 import io.fd.honeycomb.v3po.impl.trans.r.impl.spi.ListVppReaderCustomizer;
 import io.fd.honeycomb.v3po.impl.trans.util.VppRWUtils;
 import java.util.ArrayList;
@@ -47,7 +48,8 @@ import org.slf4j.LoggerFactory;
 @Beta
 @ThreadSafe
 public final class CompositeListVppReader<C extends DataObject & Identifiable<K>, K extends Identifier<C>, B extends Builder<C>>
-    extends AbstractCompositeVppReader<C, B> implements ChildVppReader<C> {
+    extends AbstractCompositeVppReader<C, B> implements ChildVppReader<C>, ListVppReader<C, K>
+{
 
     private static final Logger LOG = LoggerFactory.getLogger(CompositeListVppReader.class);
 
@@ -88,11 +90,6 @@ public final class CompositeListVppReader<C extends DataObject & Identifiable<K>
             customizer);
     }
 
-    @Override
-    protected List<C> readCurrent(@Nonnull final InstanceIdentifier<C> id) {
-        return shouldReadAll(id) ? readList(id) : super.readCurrent(id);
-    }
-
     @Override
     public void read(@Nonnull final InstanceIdentifier<? extends DataObject> id,
                      @Nonnull final Builder<? extends DataObject> parentBuilder) {
@@ -103,7 +100,9 @@ public final class CompositeListVppReader<C extends DataObject & Identifiable<K>
         customizer.merge(parentBuilder, ifcs);
     }
 
-    private List<C> readList(@Nonnull final InstanceIdentifier<C> id) {
+    @Override
+    @Nonnull
+    public List<C> readList(@Nonnull final InstanceIdentifier<C> id) {
         LOG.trace("{}: Reading all list entries", this);
         final List<K> allIds = customizer.getAllIds(id);
         LOG.debug("{}: Reading list entries for: {}", this, allIds);
@@ -113,20 +112,14 @@ public final class CompositeListVppReader<C extends DataObject & Identifiable<K>
             final InstanceIdentifier.IdentifiableItem<C, K> currentBdItem =
                 VppRWUtils.getCurrentIdItem(id, key);
             final InstanceIdentifier<C> keyedId = VppRWUtils.replaceLastInId(id, currentBdItem);
-            final List<? extends DataObject> read = readCurrent(keyedId);
-            checkState(read.size() == 1);
-            final DataObject singleItem = read.get(0);
+            final Optional<C> read = readCurrent(keyedId);
+            final DataObject singleItem = read.get();
             checkArgument(getManagedDataObjectType().getTargetType().isAssignableFrom(singleItem.getClass()));
             allEntries.add(getManagedDataObjectType().getTargetType().cast(singleItem));
         }
         return allEntries;
     }
 
-     private boolean shouldReadAll(@Nonnull final InstanceIdentifier<? extends DataObject> id) {
-        final InstanceIdentifier instanceIdentifier = id.firstIdentifierOf(getManagedDataObjectType().getTargetType());
-        return instanceIdentifier == null || instanceIdentifier.isWildcarded();
-    }
-
     @Override
     protected void readCurrentAttributes(@Nonnull final InstanceIdentifier<C> id, @Nonnull final B builder) {
         customizer.readCurrentAttributes(id, builder);
index 4e50e5a..0777425 100644 (file)
@@ -18,12 +18,15 @@ package io.fd.honeycomb.v3po.impl.trans.r.util;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
+import com.google.common.base.Optional;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.LinkedListMultimap;
 import com.google.common.collect.Multimap;
+import io.fd.honeycomb.v3po.impl.trans.r.ListVppReader;
 import io.fd.honeycomb.v3po.impl.trans.r.ReaderRegistry;
 import io.fd.honeycomb.v3po.impl.trans.r.VppReader;
 import io.fd.honeycomb.v3po.impl.trans.util.VppRWUtils;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import javax.annotation.Nonnull;
@@ -62,15 +65,27 @@ public final class DelegatingReaderRegistry implements ReaderRegistry {
         final Multimap<InstanceIdentifier<? extends DataObject>, DataObject> objects = LinkedListMultimap.create();
         for (VppReader<? extends DataObject> rootReader : rootReaders.values()) {
             LOG.debug("Reading from delegate: {}", rootReader);
-            final List<? extends DataObject> read = rootReader.read(rootReader.getManagedDataObjectType());
-            objects.putAll(rootReader.getManagedDataObjectType(), read);
+
+            if(rootReader instanceof ListVppReader) {
+                final List<? extends DataObject> listEntries =
+                    ((ListVppReader) rootReader).readList(rootReader.getManagedDataObjectType());
+                if(!listEntries.isEmpty()) {
+                    objects.putAll(rootReader.getManagedDataObjectType(), listEntries);
+                }
+            } else {
+                final Optional<? extends DataObject> read = rootReader.read(rootReader.getManagedDataObjectType());
+                if(read.isPresent()) {
+                    objects.putAll(rootReader.getManagedDataObjectType(), Collections.singletonList(read.get()));
+                }
+            }
         }
+
         return objects;
     }
 
     @Nonnull
     @Override
-    public List<? extends DataObject> read(@Nonnull final InstanceIdentifier<? extends DataObject> id) {
+    public Optional<? extends DataObject> read(@Nonnull final InstanceIdentifier<? extends DataObject> id) {
         final InstanceIdentifier.PathArgument first = checkNotNull(
             Iterables.getFirst(id.getPathArguments(), null), "Empty id");
         final VppReader<? extends DataObject> vppReader = rootReaders.get(first.getType());
index 62ddf5c..f4b2faa 100644 (file)
@@ -28,7 +28,6 @@ import static org.mockito.MockitoAnnotations.initMocks;
 import com.google.common.base.Optional;
 import com.google.common.util.concurrent.CheckedFuture;
 import io.fd.honeycomb.v3po.impl.trans.r.ReaderRegistry;
-import java.util.Collections;
 import java.util.Map;
 import org.junit.Before;
 import org.junit.Test;
@@ -79,7 +78,7 @@ public class VppOperationalDataTreeTest {
         doReturn(id).when(serializer).fromYangInstanceIdentifier(yangId);
 
         final DataObject dataObject = mock(DataObject.class);
-        doReturn(Collections.singletonList(dataObject)).when(reader).read(id);
+        doReturn(Optional.of(dataObject)).when(reader).read(id);
 
         when(serializer.toNormalizedNode(id, dataObject)).thenReturn(entry);
         final DataContainerChild<?, ?> expectedValue = mock(DataContainerChild.class);
index cdb3024..f44ca52 100644 (file)
 package io.fd.honeycomb.v3po.impl.vppstate;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.anyString;
 
+import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Multimap;
 import io.fd.honeycomb.v3po.impl.trans.r.VppReader;
+import io.fd.honeycomb.v3po.impl.trans.r.impl.CompositeListVppReader;
 import io.fd.honeycomb.v3po.impl.trans.r.impl.CompositeRootVppReader;
 import io.fd.honeycomb.v3po.impl.trans.r.util.DelegatingReaderRegistry;
 import java.util.Collections;
@@ -42,6 +45,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.Version;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.VersionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.L2Fib;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.L2FibKey;
@@ -162,20 +166,19 @@ public class VppStateTest {
 
     @Test
     public void testReadSpecific() throws Exception {
-        final List<? extends DataObject> read = readerRegistry.read(InstanceIdentifier.create(VppState.class));
-        assertEquals(read.size(), 1);
-        assertVersion((VppState) read.get(0));
+        final Optional<? extends DataObject> read = readerRegistry.read(InstanceIdentifier.create(VppState.class));
+        assertTrue(read.isPresent());
+        assertVersion((VppState) read.get());
     }
 
     @Test
     public void testReadBridgeDomains() throws Exception {
-        VppState readRoot = (VppState) readerRegistry.read(InstanceIdentifier.create(VppState.class)).get(0);
+        VppState readRoot = (VppState) readerRegistry.read(InstanceIdentifier.create(VppState.class)).get();
 
-        List<? extends DataObject> read =
+        Optional<? extends DataObject> read =
             readerRegistry.read(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class));
-//        System.err.println(read);
-        assertEquals(read.size(), 1);
-        assertEquals(readRoot.getBridgeDomains(), read.get(0));
+        assertTrue(read.isPresent());
+        assertEquals(readRoot.getBridgeDomains(), read.get());
     }
 
     /**
@@ -184,86 +187,68 @@ public class VppStateTest {
     @Test
     public void testReadL2Fib() throws Exception {
         // Deep child without a dedicated reader with specific l2fib key
-        List<? extends DataObject> read =
+        Optional<? extends DataObject> read =
             readerRegistry.read(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child(
                 BridgeDomain.class, new BridgeDomainKey("bdn1"))
                 .child(L2Fib.class, new L2FibKey(new PhysAddress("01:02:03:04:05:06"))));
-//        System.err.println(read);
-        assertEquals(read.size(), 1);
+        assertTrue(read.isPresent());
 
         // non existing l2fib
         read =
             readerRegistry.read(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child(
                 BridgeDomain.class, new BridgeDomainKey("bdn1"))
                 .child(L2Fib.class, new L2FibKey(new PhysAddress("FF:FF:FF:04:05:06"))));
-//        System.err.println(read);
-        assertEquals(read.size(), 0);
-    }
-
-    /**
-     * L2fib does not have a dedicated reader, relying on auto filtering
-     */
-    @Test
-    public void testReadL2FibAll() throws Exception {
-        // Deep child without a dedicated reader
-        final InstanceIdentifier<L2Fib> id = InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child(
-                BridgeDomain.class, new BridgeDomainKey("bdn1")).child(L2Fib.class);
-        final List<? extends DataObject> read = readerRegistry.read(id);
-//        System.err.println(read);
-        assertEquals(read.toString(), read.size(), 2);
-
-        // test if direct read returns the same value
-        final List<? extends DataObject> read2 = vppStateReader.read(id);
-//        System.err.println(read);
-        assertEquals(read, read2);
+        assertFalse(read.isPresent());
     }
 
     @Test
     public void testReadBridgeDomainAll() throws Exception {
-        VppState readRoot = (VppState) readerRegistry.read(InstanceIdentifier.create(VppState.class)).get(0);
+        VppState readRoot = (VppState) readerRegistry.read(InstanceIdentifier.create(VppState.class)).get();
 
-        final List<? extends DataObject> read =
-            readerRegistry.read(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child(
+        final CompositeListVppReader<BridgeDomain, BridgeDomainKey, BridgeDomainBuilder> bridgeDomainReader =
+            VppStateUtils.getBridgeDomainReader(api);
+
+        final List<BridgeDomain> read =
+            bridgeDomainReader.readList(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child(
                 BridgeDomain.class));
-//        System.err.println(read);
-        assertEquals(read.size(), 2);
+
         assertEquals(readRoot.getBridgeDomains().getBridgeDomain(), read);
     }
 
     @Test
     public void testReadBridgeDomain() throws Exception {
-        VppState readRoot = (VppState) readerRegistry.read(InstanceIdentifier.create(VppState.class)).get(0);
+        VppState readRoot = (VppState) readerRegistry.read(InstanceIdentifier.create(VppState.class)).get();
 
-        final List<? extends DataObject> read =
+        final Optional<? extends DataObject> read =
             readerRegistry.read(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child(
                 BridgeDomain.class, new BridgeDomainKey("bdn1")));
 
-        assertEquals(read.size(), 1);
+        assertTrue(read.isPresent());
         assertEquals(Iterables.find(readRoot.getBridgeDomains().getBridgeDomain(), new Predicate<BridgeDomain>() {
             @Override
             public boolean apply(final BridgeDomain input) {
                 return input.getKey().getName().equals("bdn1");
             }
-        }), read.get(0));
+        }), read.get());
     }
 
+    // FIXME
     @Ignore("Bridge domain customizer does not check whether the bd exists or not and fails with NPE, add it there")
     @Test
     public void testReadBridgeDomainNotExisting() throws Exception {
-        final List<? extends DataObject> read =
+        final Optional<? extends DataObject> read =
             readerRegistry.read(InstanceIdentifier.create(VppState.class).child(BridgeDomains.class).child(
                 BridgeDomain.class, new BridgeDomainKey("NOT EXISTING")));
-        assertEquals(read.size(), 0);
+        assertFalse(read.isPresent());
     }
 
     @Test
     public void testReadVersion() throws Exception {
-        VppState readRoot = (VppState) readerRegistry.read(InstanceIdentifier.create(VppState.class)).get(0);
+        VppState readRoot = (VppState) readerRegistry.read(InstanceIdentifier.create(VppState.class)).get();
 
-        List<? extends DataObject> read =
+        Optional<? extends DataObject> read =
             readerRegistry.read(InstanceIdentifier.create(VppState.class).child(Version.class));
-//        System.err.println(read);
-        assertEquals(read.size(), 1);
-        assertEquals(readRoot.getVersion(), read.get(0));
+        assertTrue(read.isPresent());
+        assertEquals(readRoot.getVersion(), read.get());
     }
 }
\ No newline at end of file
index e700d2e..7311317 100644 (file)
@@ -49,10 +49,8 @@ final class VppStateUtils {
         final ChildVppReader<Version> versionReader = new CompositeChildVppReader<>(
             Version.class, new VersionCustomizer(vppApi));
 
-        final CompositeListVppReader<BridgeDomain, BridgeDomainKey, BridgeDomainBuilder>
-            bridgeDomainReader = new CompositeListVppReader<>(
-            BridgeDomain.class,
-            new BridgeDomainCustomizer(vppApi));
+        final CompositeListVppReader<BridgeDomain, BridgeDomainKey, BridgeDomainBuilder> bridgeDomainReader =
+            getBridgeDomainReader(vppApi);
 
         final ChildVppReader<BridgeDomains> bridgeDomainsReader = new CompositeChildVppReader<>(
             BridgeDomains.class,
@@ -69,4 +67,11 @@ final class VppStateUtils {
             VppRWUtils.<VppState>emptyAugReaderList(),
             new ReflexiveRootReaderCustomizer<>(VppStateBuilder.class));
     }
+
+    static CompositeListVppReader<BridgeDomain, BridgeDomainKey, BridgeDomainBuilder> getBridgeDomainReader(
+        final @Nonnull vppApi vppApi) {
+        return new CompositeListVppReader<>(
+        BridgeDomain.class,
+        new BridgeDomainCustomizer(vppApi));
+    }
 }