Clean up DataTreeCandidateNode contract 63/81163/4
authorRobert Varga <robert.varga@pantheon.tech>
Tue, 26 Mar 2019 09:56:22 +0000 (10:56 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Tue, 26 Mar 2019 10:58:38 +0000 (11:58 +0100)
Use Optional instead of nullable and clarify that the interface
may return a UNMODIFIED node.

JIRA: YANGTOOLS-954
Change-Id: I8e394e14522a9074d503484c5893d5d5a739e4e1
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/tree/AbstractLeafCandidateNode.java
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/tree/AbstractRecursiveCandidateNode.java
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/tree/DataTreeCandidateNode.java
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/tree/DataTreeCandidateNodes.java
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/tree/EmptyDataTreeCandidateNode.java
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/tree/NormalizedNodeDataTreeCandidateNode.java
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/tree/RecursiveReplaceCandidateNode.java
yang/yang-data-api/src/test/java/org/opendaylight/yangtools/yang/data/api/schema/tree/NormalizedNodeDataTreeCandidateNodeTest.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/AbstractModifiedNodeBasedCandidateNode.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/NoopDataTreeCandidate.java

index 71b9ad0e7fdd48e7af5ac3ca0cbb68de5bad3dd5..65ee8f897d12caaf2b05393ecf37549c6dbe844a 100644 (file)
@@ -38,8 +38,8 @@ abstract class AbstractLeafCandidateNode implements DataTreeCandidateNode {
     }
 
     @Override
-    public final DataTreeCandidateNode getModifiedChild(final PathArgument identifier) {
+    public final Optional<DataTreeCandidateNode> getModifiedChild(final PathArgument identifier) {
         requireNonNull(identifier);
-        return null;
+        return Optional.empty();
     }
 }
\ No newline at end of file
index 2ae60776e68f9efd795cf6a8ebdf1a4cf6e2d6f8..a98b0fe48aa8168bb962049c82353c3b17fc9455 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.yangtools.yang.data.api.schema.tree;
 
 import com.google.common.collect.Collections2;
 import java.util.Collection;
+import java.util.Optional;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
@@ -19,8 +20,8 @@ abstract class AbstractRecursiveCandidateNode extends AbstractDataTreeCandidateN
     }
 
     @Override
-    public final DataTreeCandidateNode getModifiedChild(final PathArgument identifier) {
-        return data().getChild(identifier).map(this::createChild).orElse(null);
+    public final Optional<DataTreeCandidateNode> getModifiedChild(final PathArgument identifier) {
+        return data().getChild(identifier).map(this::createChild);
     }
 
     @Override
index b24954f8a4f5c860938df6b10cc5009b4cc397a3..1b1160d915fc4807d33a198e18545d5b80148f4d 100644 (file)
@@ -10,7 +10,6 @@ package org.opendaylight.yangtools.yang.data.api.schema.tree;
 import java.util.Collection;
 import java.util.Optional;
 import org.eclipse.jdt.annotation.NonNull;
-import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 
@@ -19,7 +18,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
  * the modification from which this candidate was created. The node itself exposes the before- and after-image
  * of the tree restricted to the modified nodes.
  */
-// FIXME: 3.0.0: Use @NonNullByDefault
+// FIXME: 4.0.0: Use @NonNullByDefault
 public interface DataTreeCandidateNode {
     /**
      * Get the node identifier.
@@ -29,22 +28,23 @@ public interface DataTreeCandidateNode {
     @NonNull PathArgument getIdentifier();
 
     /**
-     * Get an unmodifiable collection of modified child nodes.
+     * Get an unmodifiable collection of modified child nodes. Note that the collection may include
+     * {@link ModificationType#UNMODIFIED} nodes, which the caller is expected to handle as if they were not present.
      *
      * @return Unmodifiable collection of modified child nodes.
      */
     @NonNull Collection<DataTreeCandidateNode> getChildNodes();
 
     /**
-     * Returns modified child or null if child was not modified
-     * / does not exists.
+     * Returns modified child or empty. Note that this method may return an {@link ModificationType#UNMODIFIED} node
+     * when there is evidence of the node or its parent being involved in modification which has turned out not to
+     * modify the node's contents.
      *
      * @param childIdentifier Identifier of child node
-     * @return Modified child or null if child was not modified.
+     * @return Modified child or empty.
+     * @throws NullPointerException if {@code childIdentifier} is null
      */
-    // FIXME: 3.0.0: document NullPointerException being thrown
-    // FIXME: 3.0.0: return an Optional
-    @Nullable DataTreeCandidateNode getModifiedChild(PathArgument childIdentifier);
+    @NonNull Optional<DataTreeCandidateNode> getModifiedChild(PathArgument childIdentifier);
 
     /**
      * Return the type of modification this node is undergoing.
index b7cf43a06f1e90f3375586bcae9ee7ffafd5eec2..e4fa48923543ccccfa82675c2f0445262e9b2929 100644 (file)
@@ -128,9 +128,9 @@ public final class DataTreeCandidateNodes {
      *
      * @param oldData Old data container, may be null
      * @param newData New data container, may be null
-     * @return A {@link DataTreeCandidateNode} describing the change, or null if the node is not present
+     * @return A {@link DataTreeCandidateNode} describing the change, or empty if the node is not present
      */
-    public static @Nullable DataTreeCandidateNode containerDelta(
+    public static @NonNull Optional<DataTreeCandidateNode> containerDelta(
             final @Nullable NormalizedNodeContainer<?, PathArgument, NormalizedNode<?, ?>> oldData,
             final @Nullable NormalizedNodeContainer<?, PathArgument, NormalizedNode<?, ?>> newData,
             final @NonNull PathArgument child) {
@@ -138,13 +138,11 @@ public final class DataTreeCandidateNodes {
         final Optional<NormalizedNode<?, ?>> maybeOldChild = getChild(oldData, child);
         if (maybeOldChild.isPresent()) {
             final NormalizedNode<?, ?> oldChild = maybeOldChild.get();
-            if (maybeNewChild.isPresent()) {
-                return replaceNode(oldChild, maybeNewChild.get());
-            }
-            return deleteNode(oldChild);
+            return Optional.of(maybeNewChild.isPresent() ? replaceNode(oldChild, maybeNewChild.get())
+                    : deleteNode(oldChild));
         }
 
-        return maybeNewChild.isPresent() ? writeNode(maybeNewChild.get()) : null;
+        return maybeNewChild.map(DataTreeCandidateNodes::writeNode);
     }
 
     /**
index aadf58cc3aae691a632661a6d64f1477c5a54226..a582ecbcdbdcae869e3854b0ba6bfe6cac9e2c0f 100644 (file)
@@ -16,7 +16,6 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgum
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 
 final class EmptyDataTreeCandidateNode implements DataTreeCandidateNode {
-
     private final PathArgument identifier;
 
     EmptyDataTreeCandidateNode(final PathArgument identifier) {
@@ -34,8 +33,8 @@ final class EmptyDataTreeCandidateNode implements DataTreeCandidateNode {
     }
 
     @Override
-    public DataTreeCandidateNode getModifiedChild(final PathArgument childIdentifier) {
-        return null;
+    public Optional<DataTreeCandidateNode> getModifiedChild(final PathArgument childIdentifier) {
+        return Optional.empty();
     }
 
     @Override
index 359acfed734e1f66dd04e18bee4ed97873fb7111..40fb660374f37c8605872b750f8d8ab42ddc8f46 100644 (file)
@@ -49,14 +49,14 @@ final class NormalizedNodeDataTreeCandidateNode implements DataTreeCandidateNode
     }
 
     @Override
-    public DataTreeCandidateNode getModifiedChild(final PathArgument childIdentifier) {
+    public Optional<DataTreeCandidateNode> getModifiedChild(final PathArgument childIdentifier) {
         if (data instanceof NormalizedNodeContainer) {
             @SuppressWarnings({ "rawtypes", "unchecked" })
             final Optional<? extends NormalizedNode<?, ?>> child =
                 ((NormalizedNodeContainer)data).getChild(childIdentifier);
-            return child.map(input -> new NormalizedNodeDataTreeCandidateNode(input)).orElse(null);
+            return child.map(NormalizedNodeDataTreeCandidateNode::new);
         }
-        return null;
+        return Optional.empty();
     }
 
     @Override
index 74f76d994cd4f9933b54ca7badde78b9e7649b79..4330893dc5f98c8e4e2e8cf49a0302b3b28d8d23 100644 (file)
@@ -40,7 +40,7 @@ final class RecursiveReplaceCandidateNode extends AbstractDataTreeCandidateNode
     }
 
     @Override
-    public DataTreeCandidateNode getModifiedChild(final PathArgument identifier) {
+    public Optional<DataTreeCandidateNode> getModifiedChild(final PathArgument identifier) {
         return DataTreeCandidateNodes.containerDelta(oldData, data(), identifier);
     }
 
index 4ddaa57a701ffcd5884cce2f4f7ec630cda531f6..d7463ae60d4b5d0d93c1c6fa2414028c1a28c2ba 100644 (file)
@@ -5,12 +5,9 @@
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
-
 package org.opendaylight.yangtools.yang.data.api.schema.tree;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doReturn;
@@ -41,7 +38,7 @@ public class NormalizedNodeDataTreeCandidateNodeTest {
         assertTrue(childNodes instanceof List);
         assertTrue(childNodes.isEmpty());
 
-        assertNull(normalizedNodeDataTreeCandidateNode.getModifiedChild(mockedPathArgument));
+        assertEquals(Optional.empty(), normalizedNodeDataTreeCandidateNode.getModifiedChild(mockedPathArgument));
 
         assertEquals(ModificationType.WRITE, normalizedNodeDataTreeCandidateNode.getModificationType());
         assertEquals(Optional.of(mockedNormalizedNode), normalizedNodeDataTreeCandidateNode.getDataAfter());
@@ -59,10 +56,10 @@ public class NormalizedNodeDataTreeCandidateNodeTest {
         assertEquals(3, childNodes2.size());
 
         doReturn(Optional.empty()).when(mockedNormalizedNodeContainer).getChild(any(PathArgument.class));
-        assertNull(normalizedNodeDataTreeCandidateNode2.getModifiedChild(mockedPathArgument));
+        assertEquals(Optional.empty(), normalizedNodeDataTreeCandidateNode2.getModifiedChild(mockedPathArgument));
 
         doReturn(Optional.of(mockedChildNormNode1)).when(mockedNormalizedNodeContainer).getChild(
                 any(PathArgument.class));
-        assertNotNull(normalizedNodeDataTreeCandidateNode2.getModifiedChild(mockedPathArgument));
+        assertTrue(normalizedNodeDataTreeCandidateNode2.getModifiedChild(mockedPathArgument).isPresent());
     }
 }
index 6e13d2384e5e29eb178aa0b173a675ef40dbbb26..25e44a74fe66935791c2d792f24811abc2633511 100644 (file)
@@ -122,27 +122,22 @@ abstract class AbstractModifiedNodeBasedCandidateNode implements DataTreeCandida
     }
 
     @Override
-    public final DataTreeCandidateNode getModifiedChild(final PathArgument identifier) {
+    public final Optional<DataTreeCandidateNode> getModifiedChild(final PathArgument identifier) {
         switch (mod.getModificationType()) {
             case APPEARED:
             case DISAPPEARED:
             case SUBTREE_MODIFIED:
-                final Optional<ModifiedNode> childMod = mod.getChild(identifier);
-                if (childMod.isPresent()) {
-                    return childNode(childMod.get());
-                }
-                return null;
+                return mod.getChild(identifier).map(this::childNode);
             case UNMODIFIED:
                 if (!canHaveChildren(oldMeta, newMeta)) {
-                    return null;
+                    return Optional.empty();
                 }
-                final Optional<NormalizedNode<?, ?>> maybeChild = getContainer(newMeta != null ? newMeta : oldMeta)
-                        .getChild(identifier);
-                return maybeChild.isPresent() ? DataTreeCandidateNodes.unmodified(maybeChild.get()) : null;
+                return getContainer(newMeta != null ? newMeta : oldMeta).getChild(identifier)
+                        .map(DataTreeCandidateNodes::unmodified);
             case DELETE:
             case WRITE:
                 if (!canHaveChildren(oldMeta, newMeta)) {
-                    return null;
+                    return Optional.empty();
                 }
                 return DataTreeCandidateNodes.containerDelta(getContainer(oldMeta), getContainer(newMeta), identifier);
             default:
index fba541c2d88424aaee06eee6c02fb636b713ba1b..f445721946a775d241278d268745d16ae8b0c7ba 100644 (file)
@@ -54,8 +54,8 @@ final class NoopDataTreeCandidate extends AbstractDataTreeCandidate {
         }
 
         @Override
-        public DataTreeCandidateNode getModifiedChild(final PathArgument identifier) {
-            return null;
+        public Optional<DataTreeCandidateNode> getModifiedChild(final PathArgument identifier) {
+            return Optional.empty();
         }
     };